一、介绍

           开闭原则(OCP) 是面向对象设计中 “可复用设计” 的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。

 

            1988年,勃兰特·梅耶(Bertrand Meyer)在他的著作《面向对象软件构造(Object Oriented Software Construction)》中提出了开闭原则,它的原文是这样:“Software entities should be open for extension,but closed for modification”。

             翻译过来就是:“软件实体应当对扩展开放,对修改关闭”。这句话说得略微有点专业,我们把它讲的更通俗一点,也就是:软件系统中包含的各种组件,例如模(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,涌入新的功能。开闭原则中 “开” ,是指对组件功能的扩展是开放的,是允许对齐进行功能扩展的;开闭原则中 “闭” ,是指对原有代码的修改是封闭的,即修改原有的代码对外部的使用时透明的。


      二、概述

             遵循开闭原则设计出来的魔铠具有两个主要特征:

              (1)、对于扩展是开放的(Open for extension)。这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块的进项扩展,使其具有满足那些改变的新行为。也就是说,我们可以改变模块的功能。


             (2)、对于修改是关闭的(Closed for modification)。对模块行为进行扩展时,不必改动模块的源代码或则二进制代码。模块的二进制可执行版本,无论是可连接的库、DLL或则 .EXE 文件,都无需改动。


      三、实现方法

  • 抽象约束

             第一,通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法;

             第二,参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;

             第三,抽象层尽量保持稳定,一旦确定即不允许修改。

  • 元数据(metadata)控制模块行为

              元数据就是用来描述环境和数据的数据,通俗地说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

              Spring容器就是一个典型的元数据控制模块行为的例子,其中达到极致的就是控制反转(Inversion of Control)

  • 制定项目章程

              在一个团队中,建立项目章程是非常重要的,因为章程中指定了所有人员都必须遵守的约定,对项目来说,约定优于配置。

  • 封装变化

             对变化的封装包含两层含义:

             第一,将相同的变化封装到一个接口或者抽象类中;

             第二,将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。

      四、如何灵活使用开闭原则

             开闭原则指导我们,当软件需要变化时,用该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。“应该尽量”  说明 OCP原则并不是说绝对不可以修改原始类的。当我们嗅到原来的代码 “腐化气味” 时,应该尽早地重构,以便使代码恢复到正常的 “进化”过程,而不是通过继承等方式添加新的实现,这会导致类型的膨胀以及历史遗留代码的冗余。我们开发过程中也没有那么理想化的状况,完全地不用修改原来的代码,因此,在开发过程中需要自己结合具体情况进行考量,是通过修改旧代码还是通过继承使得软件系统更稳定、更灵活,在保证去除 “代码腐化” 的同时,也保证原有模块的正确性。


      五、开闭原则的好处

  • 开闭原则对测试的影响

开闭原则可是保持原有的测试代码仍然能够正常运行,我们只需要对扩展的代码进行测试就可以了。

  • 开闭原则可以提高复用性

在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来的,而不是在一个类中独立实现一个业务逻辑。只有这样代码才可以复用,粒度越小,被复用的可能性就越大。

  • 开闭原则可以提高可维护性
  • 面向对象开发的要求