【设计模式】六大基本原则
文章目录
- 开闭原则
- 里氏替换原则
- 依赖倒置原则
- 单一职责原则
- 接口隔离原则
- 迪米特原则
- 总结
开闭原则
核心就一句话:对扩展开放,对修改关闭。
针对的目标可以是语言层面的类、接口、方法,也可以是系统层面的功能、模块。当需求有变化的时候,尽量不要动已经存在的核心代码,而是围绕核心代码做扩展升级。所以,在最开始的代码设计阶段,就应该适当考虑以后可能存在的扩展点,预留一定的可扩展空间。
遵循这条设计原则,就是要保证新增特性的时候尽量不影响已有的功能,提高系统的稳定性。
但是从长远来看,系统迭代发展到一定阶段,早期的设计和实现未必能满足现阶段的需求,有可能还会成为阻碍前进的障碍。这个时候就要考虑系统重构了,不要再顾虑开闭原则,不破不立。
里氏替换原则
里氏替换主要是讲继承和多态的设计原则,设计父子关系的时候,必须确保父类特性完全适用于子类。
通俗的解释,就是子类可以在父类的基础上新增和扩展功能,但绝对不要改变父类的基础本意。也就是说,子类可以新增独属于子类的方法和功能,也可以扩展细化父类提供的方法和功能,但就是不要违背父类的意志。
设计继承最根本的目的是为了运行时能够多态替换,其基础就是父子类具有相同的特性,父类出现的地方可以被子类替代。
依赖倒置原则
讲的是分层系统设计,层与层之间如何依赖的问题。
在以前的设计架构中,通常做法是高层模块依赖底层模块,先对底层模块进行独立设计和实现,然后让高层模块引入底层模块完成相关功能。慢慢的,就会发现其中一些问题:
- 底层模块的独立性更高,但是底层模块发生变动很有可能会影响到高层模块
- 高层模块的复用性更高,别的地方引入高层模块,就必须级联引入底层模块,这会使复用变的复杂
为了解决这些问题,就提出了依赖倒置原则,反过来,让底层模块依赖高层模块。由高层模块定义出抽象层接口,由底层模块实现这些接口。
也就是说,高层模块和底层模块都依赖于抽象层接口,这样做的好处:
- 高层模块只需依赖于抽象层接口,复用将会变的简单,底层模块不会被级联引入
- 底层模块也只依赖于抽象层接口,高层模块不变的情况下,替换底层模块将会变的容易
各种数据库驱动设计,就是一个典型的依赖倒置原则应用。
单一职责原则
这里是讲编程颗粒度的问题,小到一个类和接口,大到一个功能模块,都应该有且仅有一类变化因素,如果有很多不同的变化因素,就应该拆分颗粒度,直至它的变化因素唯一,这就是单一职责。
如果一个颗粒度有太多的变化因素,可能会存在一些问题:
- 职责太多,职责之间可能会相互影响,任何一个职责变化都可能引发其它职责随之变化,牵一发而动全身
- 外界使用这个颗粒度,就必须引入全部职责,无论是否需要,这会造成职责冗余,还加深了非必要的联系
单一职责的核心就是颗粒度拥有合适的职责,提高代码实现的内聚性和灵活性。原则比较容易理解,但是想要拆分出适合的颗粒度,还是很考验开发人员的分析设计能力和相关重构经验的。
接口隔离原则
核心思想就是:要面向接口编程,不要面向实现编程。
无论是小功能还是大模块,都应该隐藏内部的代码实现,对外提供访问接口,通过接口声明它可以做的事情,功能之间、模块之间,都通过接口进行交流。
这样做的好处就是,内部实现代码是高内聚的,可以灵活调整和变通,只要接口层是稳定不变的,关联方就是无感知的,也就无需随之调整。
接口代表概念和逻辑,是抽象的,通常来讲,概念和逻辑是明确的,概念和逻辑的代码实现方式是千变万化的。所以,做系统设计的时候,首先要明确相关概念和逻辑,先用抽象层完成系统架构,再去依赖抽象层进行代码实现。
迪米特原则
形象的说法:只与你的朋友交谈,不要跟陌生人说话。
朋友是指熟悉可信任的对象,小到某个类和接口,大到功能模块系统,彼此可以直接调用和交流的都是朋友。
如果两个对象之间有交流的需求,但是又无法直接交流,或者不适合直接交流,就应用引入一个第三方作为中介,专门负责两边的沟通和联系。好处就是两边的模块都能保持各自的独立性,彼此的差异由中介去兼容和解决。
迪米特原则是系统间解耦的一种好思路,但是凡事都要有个度,过犹不及,如果引入了太多第三方中介,必然会增加系统链路之间的节点和长度,降低系统性能和稳定性,并且消息泄漏风险也会大幅增加。
总结
六大设计原则是前辈们总结出来的指导思想,合理灵活的运用能帮助我们构建出优秀的系统。但千万不要唯命是从,每个系统都有自己的重点和独特之处,结合实际情况完成设计和实现,取舍有度,适合自己的才是最好的。