OCP:开放/封闭原则

开放/封闭原则促进了协议的使用,使您能够在不更改现有代码的情况下适应应用程序的功能。

早先的“打开/关闭”原理由Bertrand Meyer在1988年定义:

“软件实体(类,模块,功能等)应打开以进行扩展,但应关闭以进行修改。”

这样的实体可以允许在不更改其源代码的情况下更改其行为。

不幸的是,Bertrand Mayer建议使用继承来实现此目标:

“类是封闭的,因为它可以被编译,存储在库中,作为基线并由客户端类使用。 但是它也是开放的,因为任何新类都可以将其用作父类,从而增加新功能。 定义后代类时,无需更改原始类或打扰其客户。”

如果子类依赖于其父类的实现细节,则继承会引入紧密耦合。

Robert C. Martin和其他人将开放/封闭原则重新定义为多态开放/封闭原则。 它使用协议而不是超类来允许不同的实现,您可以在不更改使用它们的代码的情况下轻松替换它们。 协议已关闭,无法进行修改,您可以提供新的实现方式来扩展软件的功能。

这种方法的主要好处是协议引入了额外的抽象级别,从而实现了松散耦合。 协议的实现彼此独立,不需要共享任何代码。 如果您认为协议的两个实现共享一些代码是有好处的,则可以在协议扩展中提供实现。

聪明的应用程序设计和代码编写部分应注意在应用程序的开发和维护阶段进行的频繁更改。

开放关闭原则指出,代码的设计和编写应以添加新功能的方式完成,而对现有代码的更改最少。 设计应以允许将新功能作为新类添加的方式进行,并尽可能使现有代码保持不变。

在许多方面,该原理都是面向对象设计的核心。 遵循这一原则的是可产生最大收益的面向对象技术,如可重用性和可维护性。

罗伯特·马丁(Robert Martin)引用的敏捷原则,模式和实践:

符合OCP的模块具有两个主要属性。

它们对扩展开放,这意味着可以扩展模块的行为。 随着应用程序需求的变化,我们可以使用满足这些变化的新行为来扩展模块。 换句话说,我们能够更改模块的功能。

它们已关闭以进行修改。 扩展模块的行为不会导致模块的源代码或二进制代码更改。 模块的二进制可执行版本(无论是在可链接库,DLL还是.EXE文件中)均保持不变。

TDD不仅与测试有关,更重要的是与设计有关。

有许多设计模式可以帮助我们扩展代码而不进行更改。 例如,装饰器模式可帮助我们遵循“打开关闭”原理。 同样,工厂方法,策略模式或观察者模式也可用于设计易于更改的应用程序,而只需对现有代码进行最少的更改即可。

在SRP中,您需要对分解以及代码中绘制封装边界的位置进行判断。 在OCP中,您将判断要在模块中进行哪些抽象,然后让模块的使用者进行具体设计,以及要自己提供什么具体功能。

关于这个原理,有一个有趣的类比,它指出“ 穿大衣时不需要开胸手术 。”这意味着,作为程序员,我们不应该冒险更改核心功能来添加简单功能并可能损害数据完整性。

本文在计算面积方面很好地说明了OCP的示例:

https://academy.realm.io/posts/donn-felker-solid-part-2/

让我们考虑另一个创建表单库的示例。 库为label,textField和textView提供了几个字段。

一段时间后,库开始出货,并且新的要求也开始为Switch UI提供支持。

如果在此枚举中添加新案例,并且客户端在switch语句中使用RowType ,则现有代码将中断,用户将不再使用库。

如果我们遵循开放/封闭原则,那么我们的系统将始终是可扩展的。

这些是Foundation和UIKit框架使用的“开放/封闭原则”的几个示例:

  • URLSessionConfiguration default, ephemeral
  • UILayoutPriority

https://www.brainconcert.com/articles/openclosed-principle

https://www.jessesquires.com/blog/enums-as-configs/

https://stackify.com/solid-dexfsign-open-closed-principle/

https://www.oodesign.com/open-close-principle.html


开放/封闭原则是类和接口的总体设计以及开发人员如何构建允许随时间变化的代码的指南。 通过确保您的代码对扩展开放,但对修改不开放,您就不允许将来对现有的类和程序集进行更改,这迫使程序员创建可以插入扩展点的新类。


感谢您阅读文章。

您可以在以下位置找到我:

Linkedin: Aaina Jain

推特: __aainajain