重新认识开闭原则(OCP)

2021-10-08 14:46:44 浏览数 (1)

什么是开闭原则(OCP)?

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

那怎么改动代码才算是扩展,怎么改动代码才算是修改 ?

其实这要看情况的,开闭原则可以应用在不同粒度的代码中,可以是模块,也可以是类,还可以是方法及其属性。同样一个代码改动,在粗代码粒度下,被认定为修改,在细代码粒度下,又可以被认定为扩展。

可以简单的这么理解,添加或修改业务功能,就添加或修改对应的模块(类或函数),但不会影响其余模块的单元测试,不影响其他模块的正常运行,这就属于扩展,反之就是修改,也并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。

而且,我们要认识到,添加一个新功能,不可能任何模块、类、方法的代码都不修改,这个是做不到的。类需要创建、组装、并且做一些初始化操作,才能构建成可运行的的程序,这部分代码的修改是在所难免的。我们要做的是尽量让修改操作更集中、更少、更上层,尽量让最核心、最复杂的那部分逻辑代码满足开闭原则。

如何做到对扩展开放,对修改关闭?

一个软件产品只要在其生命周期内,都会不断发生变化。变化是一个事实,所以我们需要让软件去适应变化。我们应该在设计时尽量适应这些变化,以提高项目的稳定性和灵活性,真正实现 “拥抱变化”。开闭原则告诉我们,应尽量通过扩展软件实体的行为来应对变化,满足新的需求,而不是通过修改现有代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。

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

举几个开闭原则的例子:

1、冯·诺依曼体系的中央处理器(CPU)的设计完美体现了 “开闭原则” 的架构思想。它表现在:指令是稳定的,但指令序列是变化的,只有这样计算机才能够实现 “解决一切可以用 ‘计算’ 来解决的问题” 这个目标。计算是稳定的,但数据交换是多变的,只有这样才能够让计算机不必修改基础架构却可以适应不断发展变化的交互技术革命。

2、插件机制,比如 VSCode、PyCharm、Chrome 浏览器,都可以添加插件的形式添加新的功能。

3、活字印刷术,也是开闭原则应用的一个例子。字是稳定的,字的排序是变化的。

从需求分析角度来说,关键要抓住需求的稳定点和变化点。需求的稳定点,往往是系统的核心价值点;而需求的变化点,则往往需要相应去做开放性设计。

在代码设计角度来说,我们要多花点时间往前多思考一下,这段代码未来可能有哪些需求变更、如何设计代码结构,事先留好扩展点,以便在未来需求变更的时候,不需要改动代码整体结构、做到最小代码改动的情况下,新的代码能够很灵活地插入到扩展点上,做到“对扩展开放、对修改关闭”。还有,在识别出代码可变部分和不可变部分之后,我们要将可变部分封装起来,隔离变化,提供抽象化的不可变接口,给上层系统使用。当具体的实现发生变化的时候,我们只需要基于相同的抽象接口,扩展一个新的实现,替换掉老的实现即可,上游系统的代码几乎不需要修改。

最后

开闭原则对扩展开放是为了应对变化(需求),对修改关闭是为了保证已有代码的稳定性,最终结果是为了让系统更有弹性。不过扩展性越好的代码,可读性会有所下降,也不可对简单的需求进行过度设计从而牺牲了可读性,要做好权衡,其实编程就是在权衡的艺术,为什么用这个不用那个,为什么这样设计而不是那样设计。

以上是我学习王争《设计模式之美》的学习笔记,每次看都有新的收获,常看常新,强烈推荐我的程序员朋友们加入学习

ode

0 人点赞