See also Single-Responsibility Principle

Open–Closed Principle

在面向对象编程中,开闭原则规定“软件实体(类、模块、函数等)应该对扩展开放,对修改关闭”;也就是说,这样的实体可以允许其行为在不修改源代码的情况下被扩展。

“开/闭”原则有两种用法。两种方法都使用一般化(例如,继承或委托函数)来解决明显的困境,但是目标、技术和结果是不同的。

OCP 是 SOLID 面向对象设计的五大原则之一,也是其他设计原则的基石,可以说,其他设计原则都只是实现开闭原则的一些手段。

1. History

1.1. Meyer's open/closed principle

人们普遍认为Bertrand Meyer首创了开放/封闭原则这个术语,出现在他1988年出版的《面向对象软件构造》一书中。

在Meyer撰写本文时,向库中添加字段或函数必然需要对依赖于该库的任何程序进行更改。Meyer针对这一困境提出的解决方案依赖于面向对象的继承(特别是实现继承)的概念:

1.2. Polymorphic open/closed principle

在20世纪90年代,开闭原则被广泛地重新定义,以引用抽象接口的使用:在这些接口中,可以更改实现,可以创建多个实现并以多形态的方式相互替换。

与Meyer的用法不同,这个定义主张继承抽象基类。接口规范可以通过继承重用,但实现不需要重用。现有接口不允许修改,新的实现至少必须实现该接口。

Robert C. Martin 1996年的文章“开放-封闭原则”是采用这种方法的重要著作之一。2001年,克雷格•拉尔曼(Craig Larman)将开放/封闭原则与阿利斯泰尔•考克伯恩(Alistair Cockburn)的模式(称为受保护的变异)以及戴维•帕纳斯(David Parnas)关于信息隐藏的讨论联系起来。

2. Definition

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

软件实体(类、模块、函数等)应对扩展开放,但对修改封闭。

当我们的软件实体需要变化时,要尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码。

我们知道,所有软件系统都不会一成不变,如果一个需求变化会导致多个依赖的模块都发生级联式的改动,说明程序已经呈现出“坏设计(Bad Design)”的特质了。这样的程序就会相应地变得脆弱、僵化、无法预期和无法重用。开闭原则的产生就是为了解决这些问题,它能够指导我们如何建立稳定灵活的系统,它推崇的是已经设计完成的模块应该从不改变。当需求变化时,可以通过添加新代码扩展这个模块的行为,而别去更改那些可以工作的旧代码。

3. Best Practice

本质上,开闭原则的背后,是推崇模块业务的确定性。

我们可以修改模块代码的缺陷(Bug),但不要去随意调整模块的业务范畴,增加功能或减少功能都并不鼓励。这意味着,它认为模块的业务变更是需要极其谨慎的,需要经得起推敲的。

“开闭原则”背后隐含的架构哲学,和 “架构的本质是业务的正交分解” 是一脉相承的。与其修改模块的业务,不如实现一个新业务。只要业务的分解一直被正确执行的话,实现一个新的业务模块来完成新的业务范畴,是一件极其轻松的事情。从这个角度来说,开闭原则鼓励写 “只读” 的业务模块,一经设计就不可修改,如果要修改业务就直接废弃它,转而实现新的业务模块。

这种 “只读” 思想,大家可能很熟悉。比如基于 Git 的源代码版本管理、基于容器的服务治理都是通过 “只读” 设计来改善系统的治理难度。对于架构设计来说同样如此。“只读” 的架构分解让我们逐步沉淀下越来越多可复用的业务模块。如此,我们不断坚持下去,随着时间沉淀,我们的组织就会变得很强大,组装复杂业务系统也将变得越来越简单。所以开闭原则,是架构治理的根本哲学。

4. Reference


CategoryDesignPattern