O 开闭原则
Open Closed Principle,OCP
Software entities (modules, classes, functions, etc.) should be open for extension, but closed for modification.
软件实体(模块、类、方法等)应该“对扩展开放、对修改关闭”
添加一个新的功能,应该是:在已有代码基础上扩展代码(新增模块/类/方法等)而非修改已有代码
开闭原则是为了实现代码的扩展性
在 23 种经典设计模式中,大部分都是为了解决代码的“扩展性”问题而存在的,主要遵从的就是“开闭原则”
理解的难点在于:
怎样的代码改动才被定义为‘扩展’?
怎样的代码改动才被定义为‘修改’?
开闭原则可以应用在不同粒度的代码中(模块、类、方法及其属性)
同样一个代码改动,在粗代码粒度下可能被认定为“修改”,在细代码粒度下又被认定为“扩展”
怎么才算满足或违反‘开闭原则’?
修改代码就一定意味着违反‘开闭原则’吗?
开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发
添加一个新功能是不可能任何模块、类、方法的代码都不“修改”的,我们要做的是尽量让修改操作更集中、更少、更上层,尽量让最核心、最复杂的那部分逻辑代码满足开闭原则
回到设计初衷:只要它没有破坏原有代码的正常运行,没有破坏原有的单元测试,就是一个合格的代码改动
比如参数变了,会导致调用该接口的代码都要修改(将参数封装成一个类)
比如函数体变了,会导致单元测试要修改
应用的难点在于:
如何做到‘对扩展开放、修改关闭’?
时刻具备扩展意识、抽象意识、封装意识
这些“潜意识”可能比任何开发技巧都重要
将可变部分封装起来,隔离变化,提供抽象化的不可变接口,给上层系统使用
最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如装饰、策略、模板、职责链、状态等)
关键是预留扩展点。如何才能识别出所有可能的扩展点?
若是业务导向的,就要对业务有足够的了解,能够知道当下以及未来可能要支持的业务需求
若是业务无关的、通用的、偏底层的系统(框架/组件/类库),则需要了解“它们会被如何使用?今后你打算添加哪些功能?使用者未来会有哪些更多的功能需求?”等
设计代码结构,事先留好扩展点,以便在未来需求变更的时候,在不改动代码整体结构、做到最小代码改动的情况下,将新的代码灵活地插入到扩展点上
也可以等有需求驱动的时候,再通过重构代码的方式来支持扩展的需求(没必要为一些遥远的、不一定发生的需求去提前买单,做过度设计)
如何在项目中灵活地应用‘开闭原则’,以避免在追求扩展性的同时影响到代码的可读性?
在有些情况下,代码的扩展性会和可读性相冲突
很多时候,我们都需要在扩展性和可读性之间做权衡
实际上,开闭原则讲的就是代码的扩展性问题,是判断一段代码是否易扩展的“金标准”。如果某段代码在应对未来需求变化的时候,能够做到“对扩展开放、对修改关闭”,那就说明这段代码的扩展性比较好。所以,问如何才能做到“对扩展开放、对修改关闭”,也就粗略地等同于在问:如何才能写出扩展性好的代码。
Last updated