Written by - kok-s0s
我认为对象就像生物细胞或网络上的个人电脑,只能通过消息通信(因此,消息传递是在最开始出现的 — 我们花了一些时间来了解如何在编程语言中高效地进行消息传递,并使消息传递变得更有用)。对于我来说,OOP 意味着消息传递,进程状态的本地保存、保护和隐藏,以及后期绑定。 --- Dr. Alan Curtis Kay, American computer scientist, July 23, 2003 [Ram03]
OO 是关于复杂性的处理
OO 背后的基本理念是,在软件设计中,从与我们相关的领域对事物和概念进行建模。因此,仅限于那些必须在软件系统中表示的事物,以满足利益相关者的需要,也称为需求。抽象是以适当的方式,对这些事物和概念进行建模的最重要的工具,我们不需要建模出整个现实世界,而是只需要现实世界中的一个摘录,并把它简化成与实现系统用例相关的一些细节。
类被视为封装了的软件模块,它们将结构特征(同义词:属性、数据成员、字段)和行为特征(同义词:成员函数、方法、操作)组合成一个有聚合力的单元。
类 —对象的蓝图
如果类包含几千行代码,则它们很难被理解,并且它们的可维护性和可测试性通常很差,更不用说可复用性。
避免 “上帝类” — 存在许多属性和数百个方法的异常大的类。
建议单个类的行数不超过 50 行。
不一定代码行(Line Of Code,LOC)很多就一定存在问题,一个更好的标准是类有多少项职责。
Single Responsibility Principle, SRP
每个软件单元,其中包括组件、类和函数,应该只有一个单一且明确定义的职责。
如果一个类有定义良好的职责,通常它的内聚性也会很强。
遵循 SRP 的类通常很小并且具有很少的依赖性,它们清晰、易于理解,并且非常容易测试。
所有的系统在其生命周期内都会发生变化。在开发预期比第一个版本持续时间更长的系统时,必须记住这一点。--- Ivar Jacobson, Swedish computer scientist, 1992
对于任何类型的软件单元,尤其是类设计,一个重要指南是开闭原则(OCP)。它指出软件实体(模块、类、函数等)对可扩展应该是开放的,但是对修改应该是封闭的。
在面向对象中,支持这一原则的一种方法就是继承。通过继承,可以在不修改类的情况下向类添加新功能。此外,还有许多面向对象的设计模式也支持 OCP,例如策略模式或装饰器模式。
基本上,里氏替换原则是这样说的,你不能通过给一条狗增加 4 条假腿来创造一只章鱼。--- Mario Fusco(@mariofusco),September 15,2013,on Twitter
继承是一种分类学概念,被用于构建类型的特化层次结构,即子类型是从更通用的类型派生的。
多态性通常意味着单个接口可以访问不同类型的对象。
里氏替换原则分别为类层次结构制定了以下规则:
基类的前置条件不能在派生类中增强。
基类的后置条件不能在派生类中被削弱,也就是说派生类方法的后置条件要比父类更严格。
基类的所有不变量(包括数据成员和函数成员)都不能通过派生子类更改或违反。
历史约束:对象的(内部)状态只能通过公共接口(封装)中的方法调用来改变。
使用组合而不是继承
接口是实现类之间松耦合的一种方法。
接口就像契约:类可以通过此契约请求服务,这些服务由实现该契约的其它类提供。
接口隔离原则(Interface Segregation Principle, ISP)指出接口不应该包含那些与实现类无关的成员函数,或者这些类不能以有意义的方式实现。
接口隔离原则指出,应将 “宽接口” 分离成更小且高度内聚的接口。生成的小接口也称为角色接口。
禁止!
无环依赖原则指出组件或类的依赖图应该没有环。环依赖是紧耦合的一种不良表现形式,应该不惜一切代价避免其出现。
依赖倒置原则(Dependency Inversion Principle, DIP)是一种面向对象的设计原则。用于解耦软件模块。该原则指出,面向对象设计的基础不是具体软件模块的特殊属性。相反,它们的共同特性应该被合并在共享使用的抽象体(如接口)中。
Robert C. Martin 制定了如下原则:
A. 高级模块不应该依赖于低级模块,两者都应该依赖于抽象。
B. 抽象不应该依赖于细节,细节应该依赖于抽象。
允许成员函数直接调用其所在类作用域内的其它成员函数。
允许成员函数直接调用其所在类作用域内的成员变量的成员函数。
如果成员函数具有参数,则允许成员函数直接调用这些局部对象的成员函数。
如果成员函数创建了局部对象,则允许成员函数直接调用这些局部对象的成员函数。
如果上述四种类型的成员函数中的一些调用返回了一个在结构上比该类的直接相邻元素更远的对象,则应该禁止调用这些对象的成员函数。
只有数据结构的类称为“贫血类”。贫血类的问题在于,它们只是数据结构,没有任何行为。这些类通常只有数据成员,没有成员函数。
只问不说(Tell, Don’t Ask)原则指出,一个对象应该尽可能少地暴露自己的内部状态,而应该通过提供公共的方法来改变这些状态。
避免 “上帝类”
避免使用静态成员变量和静态成员函数
Top