Open-Closed 原则对重构意味着什么?

解决保护客户端免受不必要的更改和扩展服务功能之间的张力。
47 位读者喜欢这篇文章。
Brain on a computer screen

opensource.com

在他 1988 年出版的著作《 面向对象软件构造》中, Bertrand Meyer 教授将 Open-Closed 原则 定义为

“如果一个模块仍然可以扩展,则称该模块为开放的。例如,应该可以向其包含的数据结构添加字段,或者向其执行的功能集添加新元素。

“如果一个模块可以被其他模块使用,则称该模块为封闭的。这假设该模块已被赋予明确定义的、稳定的描述(信息隐藏意义上的接口)。”

更简洁的说法是

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

类似地(并且与 Meyer 的发现并行),Alistair Cockburn 定义了 受保护的变体 模式

“识别预测变化的点,并在其周围创建稳定的接口。”

这两者都与软件的易变性有关。当您需要对软件模块进行一些更改时(总是如此),连锁反应可能是灾难性的。灾难性连锁反应的根本原因是紧密耦合,因此 Open-Closed 原则和受保护的变体模式教我们如何正确地解耦各种模块、组件、函数等等。

Open-Closed 原则是否排除重构?

如果一个模块(即,命名的代码块)必须保持对任何修改封闭,这是否意味着一旦部署就不能再碰它?如果是,那么这难道不会消除任何重构的可能性吗?

如果没有重构代码的能力,您将被迫采用最终性原则。这认为不允许返工(为什么利益相关者会同意为您已经付费的东西再次付费?),您必须仔细设计您的代码,因为您只有一次机会将其做好。这与重构的原则完全矛盾。

如果您被允许扩展已部署的代码但不更改它,您是否注定要永远在瀑布河流中游泳?只有一次机会做任何事情是灾难的根源。

让我们回顾一下解决这个难题的方法。

如何保护客户端免受不必要的更改

客户端(意味着使用某些代码块的模块或函数)通过遵守最初在组件或服务中实现的协议来利用某些功能。然而,随着组件或服务不可避免地发生变化,服务或组件与各种客户端之间的原始“伙伴关系”破裂。客户端通过破裂“发现”更改,这始终是一个令人不快的意外,通常会破坏最初的信任。

客户端必须受到保护,免受这些破裂的影响。唯一的方法是在客户端和服务或组件之间引入一个抽象层。在软件工程术语中,我们将该抽象层称为“接口”(或 API)。

接口和 API 隐藏了实现。一旦您安排通过接口或 API 交付服务,您就可以摆脱更改实现代码的担忧。无论您对服务的实现进行多少更改,您的客户端都将保持不受影响。

这样,您就回到了舒适的迭代世界。您现在可以完全自由地重构、重新排列代码,并不断重新排列代码以追求更优化的解决方案。

在这种安排中,保持封闭以进行修改的是接口或 API。接口或 API 的易变性是威胁破坏服务及其客户端之间已建立信任的东西。接口和 API 必须保持对扩展开放。这种扩展发生在幕后——通过重构和添加新功能,同时保证面向公众协议的非易变性。

如何扩展服务的功能

虽然从客户端的角度来看,服务保持非易变性,但在增强其功能方面,它们也保持开放性。这种 Open-Closed 原则通过重构来实现。

例如,如果 OrderPayment 服务的第一个增量仅提供基本功能(例如,能够处理订单总额并计算销售税),则可以通过遵守 Open-Closed 原则安全地添加下一个增量。在不破坏客户端和 OrderPayment 服务之间的握手的情况下,您可以通过添加新的代码块来重构 OrderPayment API 后面的实现。

因此,第二个增量可能包含计算运费的能力。以此类推,您明白了;您可以通过遵守 Open-Closed 原则来实现受保护的变体模式。这一切都与仔细建模业务抽象有关。

接下来阅读什么
标签
User profile image.
Alex 自 1990 年以来一直从事软件开发。他目前的热情是如何将“软性”带回软件中。他坚信,我们的行业已经达到了相当高的水平,完全可以实现这个崇高的目标(即将“软性”带回软件中)。

评论已关闭。

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.