【设计模式七大原则】开闭原则
开闭原则(Open Closed Principle)
定义
软件实体应该对扩展开放,对修改关闭。
图例
分析
任何软件都需要面临一个很重要的问题,即它们的需求会随时间的推移而发生变化。当软件系统需要面对新的需求时,我们应该尽量保证系统的设计框架是稳定的。如果一个软件设计符合开闭原则,那么可以非常方便地对系统进行扩展,而且在扩展时无须修改现有代码,使得软件系统在拥有适应性和灵活性的同时具备较好的稳定性和延续性。随着软件规模越来越大,软件寿命越来越长,软件维护成本越来越高,设计满足开闭原则的软件系统也变得越来越重要。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。
在开闭原则的定义中,软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类。
- 一个软件实体类,模块和函数应该 对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
- 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化
- 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
- 可变性的封闭原则:找到系统的可变因素,将它封装起来. 这是对"开-闭"原则最好的实现. 不要把你的可变因素放在多个类中,或者散落在程序的各个角落. 你应该将可变的因素,封套起来..并且切忌不要把所用的可变因素封套在一起. 最好的解决办法是,分块封套你的可变因素!避免超大类,超长类,超长方法的出现!!给你的程序增加艺术气息,将程序艺术化是我们的目标!
意义
在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
代码实例
一个例子来进行说明,否则可能还是有点抽象。下面代码实现画图功能。
class GraphicEditor:
def drawShape(self,s):
if s.type == 1:
self.drawRectangle()
elif s.type == 2:
self.drawCirle()
def drawRectangle(self,s):
print('画一个正方形')
def drawCirle(self, s):
print("画一个圆")
class Shape:
def __init__(self, type):
self.type = type
class Rectangle(Shape): pass
class Cirle(Shape): pass
在业务发展和版本迭代的过程中我们有了新的需求,需要添加一个功能:增加一个type能够画三角形
上面的代码每次增加一个新的图形类都要修改源代码,然后再函数drawShape中加入一个if分支。违反了开闭原则。
我们需要重构下代码:
from abc import ABC
class GraphicEditor:
def drawShape(self, s):
s.drawShape
# 定义一个抽象的图形基类
class Shape(ABC):
def __init__(self, type):
self.type = type
def drawShape(self):
pass
class Rectangle(Shape):
def drawShape(self):
print('画一个正方形')
class Cirle(Shape):
def drawShape(self):
print('画一个圆')
python装饰器遵循的就是开闭原则。
优点
提高复用性,提高可维护性。
缺点
无,使用设计模式的目的就是遵循开闭原则,是程序设计的终极目标
注意事项
- 通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法,也就是扩展必须添加具体实现而不是改变具体的方法。
- 参数类型、引用对象尽量使用接口或者抽象类,而不是实现类
- 抽象层尽量保持稳定,不允许修改接口或者抽象方法的定义。
同样一个代码改动,在粗代码粒度下,被认定为“修改”,在细代码粒度下,又可以被认定为“扩展”。比如,改动一,添加属性和方法相当于修改类,在类这个层面,这个代码改动可以被认定为“修改”;但这个代码改动并没有修改已有的属性和方法,在方法(及其属性)这一层面,它又可以被认定为“扩展”。
实际上,我们也没必要纠结某个代码改动是“修改”还是“扩展”,更没必要太纠结它是否违反“开闭原则”。我们回到这条原则的设计初衷:只要它没有破坏原有的代码的正常运行,没有破坏原有的单元测试,我们就可以说,这是一个合格的代码改动。
适用场景
任何场景。开闭原则是面向对象的可复用设计的第一块基石,最基础、最重要的设计原则。
- 点赞
- 收藏
- 关注作者
评论(0)