你不必严格遵守这些原则,违背它们也不会被处以宗教刑罚。但你应当把这些原则看成警铃,若违背了其中的一条,那么警铃就会响起 。 ----- Arthur J.Riel (1)所有数据都应该隐藏在所在的类的内部。 (2)类的使用者必须依赖类的共有接口,但类不能依赖它的使用者。 (3)尽量减少类的协议中的消息。 (4)实现所有类都理解的最基本公有接口[例如,拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从ASCII描述解析等等]。 (5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。 如果类的两个方法有一段公共代码,那么就可以创建一个防止这些公共代码的私有函数。 (6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。 (7)类之间应该零耦合,或者只有导出耦合关系。也即,一个类要么同另一个类毫无关系,要么只使用另一个类的公有接口中的操作。 (8)类应该只表示一个关键抽象。 包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响,则将对包中的所有类产生影响,而对其他的包不 造成任何影响 . (9)把相关的数据和行为集中放置。 设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违反了。 (10)把不相关的信息放在另一个类中(也即:互不沟通的行为)。 朝着稳定的方向进行依赖. (11)确保你为之建模的抽象概念是类,而不只是对象扮演的角色。 (12)在水平方向上尽可能统一地分布系统功能,也即:按照设计,顶层类应当统一地共享工作。 (13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加小心。 规划一个接口而不是实现一个接口。 (14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。 (15)对包含太多互不沟通的行为的类多加小心。 这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。 (16)在由同用户界面交互的面向对象模型构成的应用程序中,模型不应该依赖于界面,界面则应当依赖于模型。 (17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据和行为的原则而违背这条原则) 。 (18)从你的设计中去除不需要的类。 一般来说,我们会把这个类降级成一个属性。 (19)去除系统外的类。 系统外的类的特点是,抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。 (20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类,特别是只有一个有意义行为的类。考虑一下那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。 (21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段,我们常会发现很多代理没有用的,应当去除。 (22)尽量减少类的协作者的数量。 一个类用到的其他类的数目应当尽量少。 (23)尽量减少类和协作者之间传递的消息的数量。 (24)尽量减少类和协作者之间的协作量,也即:减少类和协作者之间传递的不同消息的数量。 (25)尽量减少类的扇出,也即:减少类定义的消息数和发送的消息数的乘积。 (26)如果类包含另一个类的对象,那么包含类应当给被包含的对象发送消息。也即:包含关系总是意味着使用关系。 (27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。 (28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6。 当类包含多于6个数据成员时,可以把逻辑相关的数据成员划分为一组,然后用一个新的包含类去包含这一组成员。 (29)让系统功能在窄而深的继承体系中垂直分布。 (30)在实现语义约束时,最好根据类定义来实现。这常常会导致类泛滥成灾,在这种情况下,约束应当在类的行为中实现,通常是在构造函数中实现,但不是必须如此。 (31)在类的构造函数中实现语义约束时,把约束测试放在构造函数领域所允许的尽量深的包含层次中。 (32) If the semantic information that constraints rely on changes frequently, it is best to put it in a centralized 3rd-party object. (33) If the semantic information on which a constraint depends rarely changes, it is best distributed among the various classes involved in the constraint. (34) A class must know what it contains, but it cannot know who contains it. (35) Objects that share literal scope (that is, are contained by the same class) should not have a usage relationship with each other. (36) Inheritance should only be used to model specialization hierarchies. (37) Derived classes must know the base class, and base classes should not know any information about their derived classes. (38) All data in the base class should be private, do not use protected data. Class designers should never put things in public interfaces that are not needed by users of the class. (39) In theory, the inheritance hierarchy should be deeper, the deeper the better. (40) In practice, the depth of the inheritance hierarchy should not exceed the short-term memory capacity of an average person. A widely accepted depth value is 6. (41) All abstract classes should be base classes. (42) All base classes should be abstract classes. (43) Put commonalities in data, behavior, and/or interfaces as high-end as possible in the inheritance hierarchy. (44) If two or more classes share common data (but no common behavior), then the common data should be placed in a class that is included in each class that shares this data. (45) If two or more classes have common data and behavior (that is, methods), then each of these classes should inherit from a common base class that represents these data and methods. (46) If two or more classes share a common interface (referring to messages, not methods), then they should inherit from a common base class only if they need to be used polymorphically. (47) The case-by-case analysis of the display of object types is generally wrong. In most such cases, designers should use polymorphism. (48) Case-by-case analysis of the display of attribute values is often wrong. Classes should be decoupled into an inheritance hierarchy, with each attribute value transformed into a derived class. (49) Do not model the dynamic semantics of a class through inheritance relationships. Attempting to model dynamic semantics with static semantic relations results in switching types at runtime. (50)Do not turn class objects into derived classes. Be careful with any derived class that has only one instance. (51) If you think you need to create a new class at runtime, take a step back and realize that you are creating objects. Now, generalize these objects into a class. (52) It should be illegal to use an empty method (that is, a method that does nothing) in a derived class to override a method in the base class. (53) Don’t confuse optional inclusion with the need for inheritance. Modeling optional inclusion as inheritance leads to a proliferation of classes. (54) When creating inheritance hierarchies, try to create reusable frameworks rather than reusable components. (55) If you use multiple inheritance in your design, assume you made a mistake. If you didn't make a mistake, you need to try to prove it. (56) As long as inheritance is used in object-oriented design, ask yourself two questions: (1) Is the derived class a special type of the thing it inherits? (2) Is the base class part of the derived class? (57) If you find multiple inheritance in an object-oriented design, make sure that no base class is actually a derived class of another base class. (58) In object-oriented design, if you need to choose between inclusion and association, please choose inclusion. (59) Do not use global data or global functions for bookkeeping of class objects. Class variables or class methods should be used. (60) Object-oriented designers should not let physical design principles undermine their logical design. However, we often use physical design criteria in making decisions about logical design. (61) Do not bypass the public interface to modify the state of the object.