OOD原则
一.单一职责原则(The Sigle Responsibility Principle -----SRP)
一个类只能因为一个因素而改变,不然则导致”易碎性”,因为任何一个因素导致变化都会要修改这个类,尽管这些因素可能没有一点关系。
二.开放-封闭原则(The Open-Close Principle ---OPC)
1. “对于扩展是开放的”(Open for extension)
这意味着模块的行为时可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。
2. “对于更改是封闭的”(Closed fo modification)
对模块行为进行扩展时,不必改动模块的源代码,模块的二进制可执行版本,无论是可链接库,DLL或者JAVA的.jar文件,都无需改动。
关键是抽象 模块可以操作一个抽象体。由于模块依赖一个固定的抽象体,所以它对于更改可以是关闭的。同时,通过从这个抽象体派生,也可以扩展此模块的行为。
如上图所示,如果Client需要一个不同的服务器类,那么只需要从ClientInterface接口派生一个新的类,无需对Client类做任何改动。
我们如何知道哪个变化有可能发生呢?我们进行适当的调查,提出正确的问题,并且使用我们的经验和一般常识。最终,我们会一直等到变化发生时才采取行动。
4. 尽早的发布软件。尽可能快地,尽可能频繁地把软件展示给客户和使用人员。
对于应用程序中的每个部分都肆意地进行抽象不是一个好主意。正确的做法是,开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。
三.里氏替换原则(The Liskov Substitution Principle --LSP)
void Square::SetWidth(double w)
void Square::SetHeight(double h)
这样,当设置Square对象的宽时,它的长也会相应地改变。当设置长的时候,宽也会随之改变。
这个函数认为传递进来的一定时Rectangle,并调用了其成员函数SetWidth和SetHeight。对于Rectangle来说,此函数运行正确,但如果传递进来的是Square对象就会发生断言错误。
那么究竟是怎么回事呢?Square和Rectangle这个显然合理的模型为什么会有问题?毕竟,Square应该是Rectangle。难道它们之间不存在IS-A关系?
四.依赖倒置原则(The Dependency Inversion Priciple ---DIP)
Booch曾经说过:"所有结构良好的面向对象构架都具有清晰的层次定义,每个层次通过一个定义良好的,受控的接口向外提供一组内聚的服务."对这个陈述可能会导致设计如下的结构:
下图展示了一个更为合适的模型。每个较高层次都为它所需要的服务声明一个抽象接口,较低的层次实现了这些接口,每个高层类都通过该抽象接口使用下一层,这样高层就不依赖于底层。
当然,每个程序中都会有违反该启发规则的情况。有时必须要创建具体类的实例,而创建这些实例的模块会依赖于它们。此外如果必须依赖具体类,最好依赖于不会改变的具体类,比如String。
什么是高层策略呢?它是应用背后的抽象,是那些不随具体细节的改变而改变的真理。它是系统内部的系统——它是隐喻。
五.接口隔离原则(The Interface Segregation Principle --ISP)
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中一个类需要调用另一个类的方法的话,可以通过第三者转发这个调用.
会在系统内造出大量的小方法,散落在系统的各个角落.这些方法仅仅是传递间接的调用,因此系统与系统中的商业逻辑无关.当设计师试图从一张类图看出总体的构架时,这些小方法会造成迷惑和困扰.
为了克服狭义迪米特法则的缺点,可以使用依赖倒转原则,引入一个抽象的类型引用"抽象陌生人"对象,使"某人"依赖于"抽象陌生人",换言之,就是将"抽象陌生人"变成朋友.
一个模块设计得好坏的一个重要的标志就是该模块在多大的程度上将自己的内部数据与实现有关的细节隐藏起来.
信息的隐藏非常重要的原因在于,它可以使各个子系统之间脱耦,从而允许它们独立地被开发,优化,使用阅读以及修改.
迪米特法则的主要用意是控制信息的过载.在运用迪米特法则到系统的设计中时,要注意以下几点:
* 在类的划分上,应当创建有弱耦合的类.类之间的耦合越弱,就越有利于复用.
* 在类的结构设计上,每一个类都应当尽量降低成员的访问权限.