文章图片标题

系统架构设计中的开-闭原则(OCP)

分类:架构设计 作者:阳光倾城 评论:0 点击: 728 次 日期:2016-07-30

经典力学的基石是牛顿三大定律。面向对象的设计(Object Oriented Design 或 OOD)的第一块基石,便是所谓的“开-闭”原则(Open-Closed Principle,缩写为OCP)。

开-闭原则讲的是:一个软件实体应当对扩展开放,对修改关闭。

Software entities should be open for extension,but closed for modification.

在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。应当可以在不必修改源代码的情况下改变这个模块的行为。

软件系统面临新得需求时,系统的设计必须是稳定的。满足开-闭原则的设计可以给一个软件系统两个无可比拟的优越性:

1.通过扩展已有的软件系统,可以提供新的行为,满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性

2.已有的软件模块,特别是最重要的抽象层模块不能再修改,这使得变化中的软件系统有一定的稳定性和延续性

具有这两个优点的系统是一个在高层次上实现了复用的系统,也是一个易于维护的系统。

 

如何做到“开-闭”原则

用面向对象的语言来讲,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层

解决问题的关键在于恰当的抽象化。可以给系统定义出一个一劳永逸、不再更改的抽象设计,此设计允许有无穷无尽的行为在实现层被实现。给出一个或多个抽象类或接口,规定出所有的具体类必须提供的方法的特征作为系统设计的抽象层。这个抽象层预见了所有的可能扩展,满足在任何扩展下都不会改变。这样系统的抽象层不需要修改,对修改关闭。

从抽象层导出的一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展是开放的

对可变性采取封装原则,允许发生变化同时保证变化不导致重新设计。

对可变性封装原则意味着两点:

1)一种可变性不应当散落在代码的多角落里,而应当被封装到一个对象里面。同一种可变性的不同表象意味着同一个继承等级结构中的具体子类。

继承是封装变化的方法之一。

2)一种可变性不应当与另一种可变性混合在一起。超过两层的继承结构,往往意味着将两种不同的可变性混合在了一起。

以上从工程的角度讲解了如何实现“开-闭”原则。

很多情况下,无法百分之百做到“开-闭”原则。

 

“开-闭”原则与其他设计原则的关系

里氏代换原则,任何基类可以出现的地方,子类一定可以出现。

抽象化是实现“开-闭”原则的关键步骤。基类与子类的继承关系就是抽象化的具体体现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

一般地,违反里氏代换原则的,也违背“开-闭”原则,反过来不一定成立。

 

依赖倒转原则,要依赖于抽象,不要依赖于实现。

“开-闭”原则是目标,而依赖倒转原则则是达到目标的手段。

合成/聚合复用原则,要尽量使用合成/聚合,而不是继承关系达到复用的目的。

合成/聚合复用原则是与里氏代换原则相辅相成的,两者又都是对实现“开-闭”原则的具体步骤的规范。前者要求考虑合成/聚合关系,后者要求在使用继承关系时,必须确定这个关系时符合一定条件的。

迪米特法则,一个软件实体应当与尽可能少的其他实体发生相互作用。

需要扩展的系统,会有一些模块需要修改的压力大于其他模块,如果这些模块是独立的,就不会将修改的压力传递给其他模块。

接口隔离原则,应当为客户端提供尽可能小的单独的接口,而不是提供大的总接口。

策略模式对“开-闭”原则的支持

基于对可变性的封装原则,达到“开-闭”原则的范例之一。

针对一系列算法,将每个算法封装起来,达到相互替代的目标,这就是“即插即用”,这就需要给这些对象定义相同的接口,也就需要一个抽象策略角色作为这些对象所组成的等级结构的超类型。

image

对可变性的封装原则是所有设计模式的主题:

简单工厂模式:

开闭原则对产品的消费角色成立,对于工厂角色不成立,每次新增新产品,都需要修改工厂角色,产品消费者不需要修改。

image

工厂方法模式:

具体工厂类都有共同的接口,“生产”出很多的处于同一等级的产品对象。使用这个设计的系统可以允许向系统加入新的产品类型,而不必修改已有的代码,只需要再加入一个相应的新的具体工厂类就可以了。

image

 

抽象工厂模式:

封装了产品对象家族的可变化性,一方面可以使系统动态地决定将哪个产品族实例化,另一方面可以在新的产品对象引进到已有的系统中时不必修改已有的系统。

image

 

建造模式:

封装了建造一个有内部结构的产品对象的过程,因此,这样的系统是向产品内部表象的改变开放的。建造模式的简略类图如下:

image

桥梁模式:

充分体现“对可变性的封装”。具体实现类代表不同的实现逻辑,但是所有具体实现类又有共同的接口。新的实现逻辑可以通过创建新的具体实现类加入到系统里面。

image

 

门面模式:

一个系统与某一个子系统耦合在一起,后来要换成另一个子系统,那么门面模式便可以发挥门面模式和适配器模式两种作用,将新的子系统仍然与本系统耦合在一起。这样,门面模式可改变子系统内部功能而不影响到客户端。

image

调停者模式:

使用一个调停者对象协调各个同事对象的相互作用,这些同事对象不再发生直接的相互作用。

image

这样,新增的同事对象加入到系统中的时候,不会影响其他已有的同事对象,但是调停者本身需要修改。

访问者模式:

使得在节点中加入新的方法变得很容易,仅仅需要在一个新的访问者类中加入此方法即可。但是不能很好地处理新增节点的情况。

方法集合的可扩展性和类集合的不可扩展性。

image

迭代子模式:

将访问聚集元素的逻辑封装起来,并且使它独立于聚集对象的封装。提供了聚集存储逻辑与迭代逻辑独立演变的空间,使系统可以在无需修改迭代子的客户端的情况下,对聚集对象的内部结构进行功能扩展。

image




声明: 除非注明,本文属( 阳光倾城 )原创,转载请保留链接: http://www.tomrrow.com/archives-7745.html