前言:所有的原则缩写都是英文的首字母,如开闭原则(Open Closed Principle)是OCP。
总结场景:
先总结一一各个原则的作用。
- 开闭原则:六大原则里的一个基础。其他原则都是他的实现或更严格的规范约束。
- 接口隔离原则:类只服务于一个单一的模块(模块这个概念是一个虚的,需要具体项目具体分析)。
- 单一职责原则:每个类只有一种作用。
- 里氏替换原则:父类与子类实现继承关系时,减少(继承的)负面影响。
- 依赖倒置原则:设计类与类之间的关系时,减少调用方与被调用方实体之间的关联关系。
- 迪米特原则:从函数的维度,规则调用方与被调用方的职责与联系。
开闭原则(Open Closed Principle)
核心
Software entities like classes, modules and functions should be open for extension but closed for modifications.
对扩展开放,对修改关闭。
作用
定义了新增和修改代码时的理想方案。
优缺点
优点:对旧代码无影响,修改或新增功能时,只需要开发和测试的时候新增部分。
缺点:对于只需要改原来代码一两行的情况,需要做重构或新增函数做修改,量比较大。开闭原则使用场景受限,一般只应用于对代码要求很严格的项目。
接口隔离原则 (Interface Segregation Principle)
核心
- 客户端不应该依赖它不需要的接口。
- 类间的依赖关系应该建立在最小的接口上。
简而言之,理想情况接口只服务于一个模块,不可以被多个模块使用。
作用
给出了接口划分的方法论。
优缺点
优点:
- 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
- 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
- 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
- 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。
缺点:不适用于小型项目;接口划分后,数量会增加,提升开发复杂度。
单一职责原则(Single Responsibility Principle)
核心
每一个类的职责唯一。
上面那句话看起来就是一句废话,我举例:现在有一个用户类,有属性(姓名,年龄)和动作(上班、回家)。但是类中的方法就包括了【维护属性的函数】(我们叫BO)和【维护动作的函数】(BIZ)。这种情况下用户类的职责就不是唯一的。所以需要拆成两个类。一个只维护用户信息,一个只维护用户动作。
作用
明确一个类所负责的范围,用于定义类。
优缺点
优点:
-
类的复杂性降低,实现什么职责都有清晰明确的定义;
-
可读性提高,复杂性减低,可读性当然提高;
-
可维护性提高,可读性提高,可维护性当然提高;
-
变更引起的风险减低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的类有影响,对其他接口无影响,这对系统的扩展性、维护性都有非常大的帮助。
缺点:类拆分后类的数量会增加。
单一职责与接口隔离的区别:
- 根据接口隔离原则拆分接口时,类必须满足单一职责原则。
- 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。
- 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。
里氏替换原则(Liskov Substitution Principel)
核心
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类可以有个性化方法。
- 当子类的方法重载父类的方法时,子类方法形参比父类形参更宽松,即子类的参数是父类参数的父类型(大于等于的关系)。
- 当子类的方法实现父类的抽象方法时,子类方法返回是父类方法的子类型(小于等于的关系)。
概括:父类出现的地方子类都可以出现,子类出现的地方父类不一定可以(继承的本质)。
作用
- 克服了继承中重写父类造成的可复用性变差的缺点。
- 保证类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
- 实现开闭原则的重要方式。
优缺点
继承的优点:
- 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
- 提高代码的重用性;
- 子类可以形似父类,但又异于父类;
- 提高代码的可扩展性;
- 提高产品或项目的开放性。
继承的缺点:
- 继承是侵入性的,只要继承就必须拥有父类的所有属性和方法;
- 降低代码的灵活性,子类必须拥有父类的属性和方法,让子类增加了约束;
- 增强了耦合性,当父类的常量、变量和方法被修改时,必须考虑子类的修改。
依赖倒置原则 (Dependence Inversion Principle)
核心
High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions.
- 高层模块实现不依赖于低层模块。
- 实现模块依赖于抽象模块,抽象模块不依赖于实现模块。
作用
通过要面向接口的编程来降低类间的耦合性,要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类。
优缺点
优点:抽象类(对外暴露的类)更通用。
缺点:抽象类与实现类耦合太紧密。
迪米特原则(Law of Demeter)(Least Knowledge Principle)
核心
Talk only to your immediate friends and not to strangers.
只关注friend。出现在成员变量、方法的输入输出参数中的类称为friend类,而出现在方法体内部的类不属于friend类。
作用
限制软件实体之间通信的宽度和深度。
如果两个类无须直接通信,那么就不应当发生直接的相互调用,可以通过第三个类转发该调用。(老公,老婆,老婆的公司)
从迪米特法则的定义和特点可知,它强调以下两点:
- 从依赖者的角度来说,只依赖应该依赖的对象。
- 从被依赖者的角度说,只暴露应该暴露的方法。
优缺点
优点:解耦 ,增加类的可复用率和系统的扩展性。
缺点:过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。