标签:
1. 开闭原则(Open-Closed Principle,OCP)
1)定义:一个软件实体应当对扩展开放,对修改关闭( Software entities should be open for extension,but closed for modification.)。即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。
2)满足“开-闭”原则的系统的优点:
a)通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。
b)已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。
c)这样的系统同时满足了可复用性与可维护性。
3)如何实现“开闭原则”:
在面向对象设计中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。换言之,定义一个一劳永逸的抽象设计层,允许尽可能多的行为在实现层被实现。
在面向对象编程中,通过抽象类及接口,规定了具体类的特征作为抽象层,相对稳定,不需更改,从而满足“对修改关闭”;而从抽象类导出的具体类可以改变系统的行为,从而满足“对扩展开放”。
4)对可变性的封装原则:
a)一种可变性不应当散落在代码的许多角落,而应当被封装到一个对象里面。同一可变性的不同表象意味着同一个继承等级结构中的具体子类。因此,此处可以期待继承关系的出现。继承是封装变化的方法,而不仅仅是从一般的对象生成特殊的对象。
b)一种可变性不应当与另一种可变性混合在一起。类图的继承结构如果超过两层,很可能意味着两种不同的可变性混合在了一起。
“开-闭”原则(Open-Closed Principle)是面向对象的可复用设计(Object Oriented Design或OOD)的基石。其他设计原则(里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则)是实现“开-闭”原则的手段和工具。所以,以下原则是附属于“开-闭”原则的。
2. 里氏替换原则(Liskov Substitution Principle,LSP)
1)任何基类可以出现的地方,子类一定可以出现。也就是说,在软件里面,把基类都替换成它的子类,程序的行为没有变化。
2)与“开-闭”原则的关系:
是对“开-闭”原则的补充,是对实现抽象化的具体步骤的规范。
3)违反里氏代换原则意味着违反了“开-闭”原则,反之未必。
例子:正方形不是长方形的子类
解决办法:发明一个四边形类,然后让长方形和正方形变成它的具体子类。这样就解决了长方形和正方形的关系不符合里氏替换原则的问题。
3. 依赖倒转原则(Dependence Inversion Principle,DIP)
1)依赖倒转原则就是要依赖于抽象,不要依赖于实现。要针对接口编程,不要针对实现编程。传统的过程性系统的设计办法倾向于使高层次的模块依赖于低层次的模块,抽象层次依赖于具体层次。倒转原则就是把这个错误的依赖关系倒转过来。
2)与“开-闭”原则的关系:
目标和手段的关系——“开-闭”原则是目标,达到这一目标的手段是依赖倒转原则;换言之,要想实现“开-闭”原则就应该坚持依赖倒转原则,违反依赖倒转原则,就不可能达到“开-闭”原则的要求。
3)与里氏代换原则的关系:
里氏替换原则是依赖倒转原则的基础,依赖倒转原则是里氏代换原则的重要补充。
例子:工厂模式
4. 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
1)在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的。
2)什么是合成?什么是聚合?
聚合表示整体和部分的关系,表示“拥有”。如奔驰S360汽车,对奔驰S360引擎、奔驰S360轮胎的关系是聚合关系,离开了奔驰S360汽车,引擎、轮胎就失去了存在的意义。在设计中, 聚合不应该频繁出现,这样会增大设计的耦合度。
合成则是一种更强的“拥有”,部分和整体的生命周期一样。
3)通过合成/聚合进行复用的优缺点:
优点:
1) 新对象存取成分对象的唯一方法是通过成分对象的接口。
2) 这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的。
3) 这种复用支持包装。
4) 这种复用所需的依赖较少。
5) 每一个新的类可以将焦点集中在一个任务上。
6) 这种复用可以在运行时间内动态进行,新对象可以动态的引用与成分对象类型相同的对象。
7) 作为复用手段可以应用到几乎任何环境中去。
缺点:就是系统中会有较多的对象需要管理。
4)通过继承来进行复用的优缺点:
优点:
新的实现较为容易,因为超类的大部分功能可以通过继承的关系自动进入子类。
修改和扩展继承而来的实现较为容易。
缺点:
继承复用破坏包装,因为继承将超类的实现细节暴露给子类。由于超类的内部细节常常是对于子类透明的,所以这种复用是透明的复用,又称“白箱”复用。
如果超类发生改变,那么子类的实现也不得不发生改变。
从超类继承而来的实现是静态的,不可能在运行时间内发生改变,没有足够的灵活性。
例子:当一个类是另一个类的角色时,应该用合成/聚合复用原则描述
5. 迪米特法则(Law of Demeter,LoD或LKP(Least Knowledge Principle))
1) 一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块。扩展会相对容易。这是对软件实体之间通信的限制。它要求限制软件实体之间通信的宽度和深度。
2) 如何实现迪米特法则:
迪米特法则的主要用意是控制信息的过载,在将其运用到系统设计中应注意以下几点:
1) 在类的划分上,应当创建有弱耦合的类。类之间的耦合越弱,就越有利于复用。
2) 在类的结构设计上,每一个类都应当尽量降低成员的访问权限。一个类不应当public自己的属性,而应当提供取值和赋值的方法让外界间接访问自己的属性。
3) 在类的设计上,只要有可能,一个类应当设计成不变类。
4) 在对其它对象的引用上,一个类对其它对象的引用应该降到最低。
3)迪米特法则与设计模式:
门面(外观)模式和调停者(中介者)模式实际上就是迪米特法则的具体应用。
6. 接口隔离原则(Interface Segregation Principle,ISP)
1) 使用多个专门的接口比使用单一的总接口要好。也就是说,一个类对另外一个类的依赖性应当是建立在最小的接口上。这里,我们可以把接口理解成角色,一个接口就只是代表一个角色,每个角色都有它特定的一个接口,这里的这个原则可以叫做\"角色隔离原则\"。
2) 遵循迪米特法则和接口隔离原则,会使一个软件系统功能扩展时,修改的压力不会传到别的对象那里。
7. 单一职责原则(Single Response Principle,SRP)
一个类只能因为一个因素而改变,不然则导致”易碎性”,因为任何一个因素导致变化都会要修改这个类,尽管这些因素可能没有一点关系。
例如:以下程序中Modem接口。看起来非常合理。该接口声明的4个函数确实是Modem所具有的功能。
interface Modem
{
public void dial(string pno);
public void hangup();
public void send(char c);
public void recv();
}
然而,该接口中确有两个职责,第一个职责是连接管理;第二个职责是数据通信。dial和hangup函数负责连接处理,而send和recv函数进行通信。所以要分开。
标签:
原文地址:http://www.cnblogs.com/bilibiliganbei/p/5578478.html