面向对象的设计原则摘要
The principles of class design:
SRP(Single Responsibility Principle)单一职责原则:一个类应该有且仅有一个职责。所谓一个类的职责是指引起该类变化的原因,如果一个类具有一个以上的职责,那么就会有多个不同的原因引起该类变化,其实就是耦合了多个互不相关的职责,就会降低这个类的内聚性。
遵循OCP原则的模块具有两个主要特征.他们是:
1. "对于扩展是开放的"(Open for extension)
这意味着模块的行为是可以扩展的。当应用的需求改变是,我们可以队模块惊醒扩展,使其具有满足哪些改变的新行为。换句话说,我们可以改变模块的功能。
2. "对于更改是封闭的"(Close for modification)"。
OCP背后的机制主要是抽象(abstraction)和多态(polymorphism)。
LSP(Liskov Substitution Principle) 里氏替换原则: 子类型(subtype)必须能够替换掉他们的基类型(base type)。 若对每个类型S的对象O1,都存在一个类型T的对象O2,使得在所有针对T编写的程序P中,用O1替换O2后,程序P行为功能不变,则S是T的子类型。
DIP(Dependency-Inversion Principles) 依赖倒置原则: 1.高层模块不应该依赖于低层模块。二者都应该依赖于抽象。2.抽象不应该依赖于细节。细节应该依赖于抽象。
由DIP可知:
任何变量都不应该持有一个指向具体类的指针或者引用.
任何类都不应该从具体类派生。
ISP (Interface Segregation Principles) 接口隔离原则: 不要强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。
如果强迫客户程序依赖于那些它们不使用的方法,那么这些客户程序就面临着由于这些未使用方法的改变所带来的变更。这无意中导致了所有客户程序之间的耦合。换句话说,如果一个客户程序依赖于一个含有它不使用的方法的类,但是其他客户程序却要使用该方法,那么当其他客户要求这个类改变时,就会影响到这个客户程序。我们希望尽可能地避免这种耦合,因此我们希望分离接口。
The principles of package cohesion:
REP (Reuse Release Equivalence Principle) 重用发布等价原则: 重用粒度就是发布粒度.
一个包的重用粒度(granule of reuse)和发布粒度(granule of release)一样大。我们所重用的任何东西都必须同时被发布和跟踪。如果一个包中的软件是用来重用的,那么它就不能再包含不是为了重用目的而设计的软件。一个包中的软件要么都是可重用,要么都是不可重用。
CRP(Common Reuse Principle)共同重用原则:
一个包中的所有类应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类。相互之间没有紧密练习的类不应该放在同一包里。
CCP(Common Closure Principle) 共同封闭原则:
包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包产生影响,则将对该包中的所有类产生影响,而对于其他的包不造成任何影响。 如果两个类之间有非常紧密的绑定关系,不管是再物理上的还是概念上的,那么他们总是会一同进行变化,因而他们应该属于同一包中。这样做会减少软件的发布、重新验证、重新发布的工作量。
The principles of package coupling:
ADP(Acyclic Dependencies Principle)无环依赖原则: 在包的依赖关系图中不允许出现环。出现了环,实际上把环内的包合成了一个大包。这种环使得对模块的隔离变得非常难;单元测试和发布变得非常困难而且易于出错;包的构建没有恰当的顺序。
解除依赖环: 使用DIP原则,依赖于抽象;或重新创建所要依赖的包。
SDP (Stable Dependencies Principle )稳定依赖原则: 朝着稳定的方向进行依赖。
对于任何包而言,如果它是可变的,就不应该让一个难以更改的包依赖于它!否则,可变的包同样也会难以更改。
计算包的位置稳定性:
(Ca)输入耦合度(Afferent Coupling): 指处于该包的外部并依赖于该包内的类的类的数目。
(Ce)输出耦合度(Efferent Coupling): 指处于该包的内部并依赖于该包外的类的类的数目。
(不稳定性I)
I = Ce/(Ca + Ce)
SDP规定一个包的I度量值应该大于它所依赖的包的I的量度值(也就是说,I度量应该顺着依赖的方向减少)。
SAP (Stable Abstractions Principle)稳定抽象原则: 包的抽象程度应该和其稳定程度一致。该原则把包的稳定性和抽象性联系起来。它规定,一个稳定的包应该也是抽象的,这样它的稳定性就使其可以灵活扩展。另一方面,一个不稳定的包应该是具体的,因为它的不稳定性使得其内部的具体代码易于修改。
抽象性度量:
A 是一个测量包抽象程度的度量标准。它的值就是包中抽象类的数目和全部类的数目的比值。
A = Nc/Na
Nc:包中类的总数。
Na:包中的抽象类的数目。请记住,一个抽象类是一个至少具有一个纯接口(pure interface)的类,并且它不能被实例话。
A:抽象性
画一个以稳定性(I)为横轴,抽象性(A)为纵轴的坐标图。
左上角(0,1)表示最稳定最抽象的,右下角(1,0)则表示最不稳定、最具体的。
主序列 (The Main Sequance): 即为两个端点的连线.A + I = 1
Zone of Uselessness 区域为无用地带,该处有最大的抽象性,却没有依赖者(不稳定)。
Zone of Pain 区域为痛苦地带,该处几乎没有什么抽象性却又过于稳定。
包的最佳位置是在主序列的两个端点上,但是做到在主序列上,或在主序列附近就很不错了。
到主序列的距离: D = |A+I-1| / √2 (根号2)
D的值越小越好,对于所有D值不在0
附近的包进行复查和调整。