面向对象的可复用设计的第一块基石,便是所谓的“开-闭”原则(Open-Closed Principle,常缩写为OCP)。
“开-闭”原则讲的是:一个软件实体应当对扩展开放,对修改关闭。英文原文是:Software entities should be open for extension,but closed for modification。
这个原则说的是,在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。换言之,应当可以在不必修改源代码的情况下改变这个模块的行为。

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

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


怎样做到“开-闭”原则?

抽象化是关键:
在Java语言里,可以给出一个或多个抽象类或抽象接口,规定出所有的具体类必须提供的方法的特征,作为系统设计的抽象层。这个抽象层预见了所有可能的扩展,因此,在任何扩展情况下都不会改变。这就使得系统的抽象层不需修改,从而满足了“开-闭”原则的第二条:对修改关闭。同时,由于从抽象层都出一个或多个新的具体类可以改变系统的行为,因此系统的设计是对扩展开放的,这就满足了“开-闭”原则的第一条。

对可变性的封装原则:
“开-闭”原则如果从另外一个角度讲述,就是所谓的“对可变性的封装原则”(Principle of Encapsulation of Variation,常常略写做EVP),讲的是找到一个系统的可变因素,将之封装起来。
考虑你的设计中什么可能会发生变化。与通常将焦点放到什么会导致设计改变的思考方式正好相反,这一思路考虑的不是什么会导致设计改变,而是考虑你允许什么发生变化而不让这一变化导致重新设计。这一思想用一句话总结为:“找到一个系统的可变因素,将它封装起来”,既“对可变性的封装原则”。这一原则意味着两点:

  • 一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。同一种可变性的不同表象意味着同一个继承等级结构中的具体子类。继承应当被看做是封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象的方法。
  • 一种可变性不应当与另一种可变性混在一起。所有的设计模式的类图的继承结构一般都不会超过两层,不然就意味着将两种不同的可变性混在了一起。


设计师应当怎样判断何时使用多态性取代条件转移语句?回答是应当从“开-闭”原则出发来做判断。如果一个条件转移语句确实封装了某种商务逻辑的可变性,那么将这种可变性封装起来就符合“开-闭”原则设计思想了。
但是,如果一个条件转移语句没有涉及重要的商务逻辑,或者不会随着时间的变化而变化,也不意味着任何的可扩展性,那么它就没有涉及任何有意义的可变性。这时候将这个条件转移语句改写成为多态性就是一种没有意义的浪费。