【java与模式】开-闭 原则

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

1. 什么是“开-闭”原则

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

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

所有的软件系统都有一个共同的性质,即对它们的需求都会随时间的推移而发生变化。在软件系统面临型的需求时 ,系统的设计必须是稳定的。满足“开-闭”原则的设计可以给一个软件系统两个无可比拟的优越性:

  • 通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。
  • 已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。

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

2. 怎么做到“开-闭”原则

乍看起来,不能修改而可以扩展似乎是互相矛盾的。怎么可以同时又不修改、而又可以扩展呢?开始讨论之前,不妨考察一下《西游记》中,玉皇大帝在美猴王的挑战之下,是怎么维护天庭的秩序的。

玉帝招安美猴王

当年大闹天宫时的美猴王便是玉帝天庭的新挑战。美猴王说:“‘皇帝轮流做,明年到我家。’只教他搬出去,将天宫让与我!”对于这项新挑战,太白金星给玉皇大帝提出的建议是:“臣启陛下……降一道招安圣旨,把他宣来上届……与他籍名……一则不动众劳,二则收仙有道也。”

换言之,不劳师动众,不破坏天规便是“闭”,收仙有道便是“开”.招安之法便是玉帝天庭的“开-闭”原则,通过给美猴王封一个“弼马温”的官职,便可使现有系统满足变化了的需求,而不必更改天庭的既有秩序。

招安之法的关键便是不允许更改现有的天庭秩序,但允许将妖猴纳入现有的秩序中,从而扩展了这一秩序。面向对象的语言来讲,不允许更改是系统的抽象类,而允许扩展的是系统的实现层。

抽象化是关键

解决问题的关键在于抽象化。在像Java语言这样的面向对象的编程语言里面,可以给系统定义一个一劳永逸、不再更改的抽象设计,此设计允许有无穷无尽的行为在实现层被实现。在Java语言里,可以给出一个或多个抽象Java类或Java接口,规定出所有的具体类必须提供的方法的特性作为系统设计的抽象层。这个抽象层预见了所有的可能扩展,因此,在任何扩展情况下都不会变化。这就使得系统的抽象层不需修改,从而满足了“开-闭”原则的第二条:对修改关闭。

同时,由于从抽象层导入一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展是开放的,这就满足了“开-闭”原则的第一条。

对可变性的封装原则

“开-闭”原则如果从另外一个角度,就是所谓的“对可变性的封装原则”,讲的是找到一个系统的可变因素,将之封装起来。
考虑你的设计中什么可能会发生变化。与通常将焦点放到什么会导致设计改变的思考方式正好相反,这一思路考虑的不是什么会导致设计改变,而是考虑你允许什么发生变化而不让这一变化导致重新设计。

将这一思想用一句话总结为:“找到一个系统的可变因素,将它封装起来”,并将它命名为“对可变性的封装原则”
“对可变性的封装原则”意味着两点:

  1. 一种可变性不应当散落在代码的很多角落,而应当被封装到一个对象里面。同一种可变性的不同表象意味着同一个继承等级结构中的具体子类,因此,读者可以期待在设计模式中看到继承关系。

继承应当被看做是封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象的方法。

  1. 一种可变性不应当与另一种可变性混合在一起。

显然“对可变性的封装原则”从工程的角度讲解了如何实现“开-闭”原则。如果能够将“对可变性的封装原则”作为总的设计原则的话,那么按照这个原则进行的系统设计,应当遵守“开-闭”原则。

与其他设计模式的关系

做到“开-闭”原则不是一件容易的工作,但是也是很多规律可循的。这些规律也同样以设计原则身份出现,但是它们都是“开-闭”原则的手段和工具,是附属于“开-闭”原则的。

里氏替换原则

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

里氏替换原则是对“开-闭”原则的补充。正如前面所谈到的,实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体体现。所以里氏替换原则是对实现抽象化的具体步骤的规范。

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

依赖倒转原则

依赖倒转原则讲的是,要依赖于抽象,不要依赖于实现。
看上去依赖倒转原则与“开-闭”原则有很大的相似之处,实际上,它们之间的关系是目标和手段之间的关系。“开-闭”原则是目标,而达到这一目标的手段是依赖倒转原则。

换言之,要想实现“开-闭”原则,就应当坚持依赖倒转原则。违反依赖倒转原则,就不可能达到“开-闭”原则的要求。

合成/聚合复用原则

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

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

遵守合成/聚合复用原则是实现“开-闭”原则的必要条件;违反这一原则就无法使系统实现“开-闭”原则这一目标。

迪米特法则

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

当一个系统面临功能扩展的时候,其中会有一些模块,它们需要修改的压力比其他一些模块要大。最后的结果可能是这些模块需要修改或者不需要修改。但是不论是哪一种情况,如果这些模块是相对孤立的,那么它们就不会将修改的压力传递给其他的模块。

这就是说,一个遵守迪米特法则设计出来的系统在功能需要扩展时,会相对更容易地做到对修改的关闭。也就是说,迪米特法则是一条通向“开-闭”原则的道路。

接口隔离原则

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

显然,接口隔离原则与广义的迪米特法则都是对一个软件实体与其他的软件实体的通信的限制。广义的迪米特法则要求尽可能限制通行的宽度和深度。接口隔离原则所限制的是通信的宽度,也就是说,通信应当尽可能地窄。

显然,遵循接口隔离原则与迪米特法则,会使一个软件系统在功能扩展的过程中,不会修改的压力传递到其他的对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值