六大设计原则
设计模式的六大原则有:
- Single Responsibility Principle:单一职责原则
- Open Closed Principle:开闭原则
- Liskov Substitution Principle:里氏替换原则
- Law of Demeter:迪米特法则
- Interface Segregation Principle:接口隔离原则
- Dependence Inversion Principle:依赖倒置原则
把这六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。
参考资料:
- 书籍《设计模式之禅》
- 简书-六大设计原则(SOLID)
- 简书-六大设计原则之依赖倒置原则(DIP)
- 本文是整理这篇文章及其内链
- CSDN-设计模式六大原则——SOLID
一、 单一职责原则
1. 概念
单一职责原则(Single Responsibility Principle, SRP ),就是一个类只负责一个职责,降低类的复杂度,维护起来更加容易。 这个原则不仅仅局限于类,对于接口和方法也同样适用。通常,接口和方法的单一职责更容易实现。
2. 特点
- 代码的粒度降低了,类的复杂度降低了。
- 可读性提高了,每个类的职责都很明确,可读性自然更好。
- 可维护性提高了,可读性提高了,一旦出现 bug ,自然更容易找到他问题所在。
- 改动代码所消耗的资源降低了,更改的风险也降低了。
二、 开闭原则
1. 概念
开闭原则(Open Closed Principle, OCP)旨在如何建立稳定灵活的系统,只定义了对修改关闭,对扩展开放。
对软件原有代码进行修改,可能会给旧代码引入错误,也有可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现。
2. 优点
用抽象构建架构,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保证架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了,当然前提是抽象要合理,要对需求的变更有前瞻性和预见性。
三、 里氏替换原则
所有引用基类的地方必须能透明地使用其子类的对象
1. 概念
里氏替换原则(Liskov Substitution Principle, LSP )是指所有基类在的地方,都可以换成子类,程序还可以正常运行。 这个原则是与面向对象语言的继承特性密切相关,是为了弥补继承的缺陷。
2. 特点
里氏替换原则对继承进行了规则上的约束,这种约束主要体现在四个方面:
- 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
- 子类中可以增加自己特有的方法。
- 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比- 父类方法的输入参数更宽松。(即只能重载不能重写)
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
四、 迪米特法则
其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
1. 概念
迪米特法则(Law of Demeter, LOD)要求限制软件实体之间通信的宽度和深度。
过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。它调以下两点:
- 从依赖者的角度来说,只依赖应该依赖的对象。
- 从被依赖者的角度说,只暴露应该暴露的方法。
2. 优点
正确使用迪米特法则将有以下两个优点。
- 降低了类之间的耦合度,提高了模块的相对独立性。
- 由于亲合度降低,从而提高了类的可复用率和系统的扩展性。
五、 接口隔离原则
注:该原则中的接口,是一个泛泛而言的接口,不仅仅指Java中的接口,还包括其中的抽象类。
1. 概念
接口隔离原则(Interface Segregation Principle, ISP)的定义:
- 客户端不应该依赖它不需要的接口。
- 类间的依赖关系应该建立在最小的接口上。
2. 优点
接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下 5 个优点。
- 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
- 接口隔离 提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
- 如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。
- 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
- 在项目工程中减少代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。
3. 实现方法
在具体应用接口隔离原则时,应该根据以下几个规则来衡量。
- 根据接口隔离原则拆分接口时,首先必须满足单一职责原则。
- 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
- 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
- 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同深入了解业务逻辑。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
4. 接口隔离原则和单一职责的区别
接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:
接口隔离原则 | 单一职责 | |
---|---|---|
注重 | 职责 | 对接口依赖的隔离 |
主要 | 约束类 | 约束接口 |
针对 | 程序中的实现和细节 | 抽象和程序整体框架的构建 |
六、 依赖倒置原则
1. 概念
依赖倒置原则(Dependence Inversion Principle)
- 上层模块不应该依赖底层模块,它们都应该依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。