单一职责原则

对于一个类而言,应该只有一个引起它变化的原因。
单一职责的划分界限总不是很清楚,很多时候都是需要靠个人经验来界定。当然,最大的问题就是对职责的定义,什么是类的职责,已经怎么划分类的职责。

开闭原则

软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。当软件需求变化时,我们应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码。

抽象化时开闭原则的关键。

对于具有相同功能的单一职责类,客户端在使用这一类的函数是,我们应该将这些类抽象出一个接口(或者抽象类),客户端值引用接口,具体设置可以传入具体的实现类。这样可以做到对修改封闭,对变化进行扩展。

比如客户端直接引用具体的实现类,当需要变化为另一种实现方式时,我们就要修改客户端的代码,更改引用。这就违背了开闭原则。

例子:加载图片的第三方框架有很多,如何能够做到在项目中快速的更换呢?我们可以定义一个接口,接口中有要实现的加载图片的功能函数,等待子类实现,图片加载工具类引入这个接口。每引入一种三方框架就写一个子类去实现这个接口。我们在图片加载工具类中通过一个 set 方法将子类注入到接口的引用上就可以了。
其实这也体现出了 里氏替换原则(所有子类都可以设置到父类的地方)、依赖倒置原则(依赖抽象,不依赖细节)。

里氏替换原则

第一种定义是:如果对每一个类型为S的对象O1,都有类型为T的对象O2,使得以T定义的所有程序P在所有的对象O1都代换 成O2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。
第二种定义:所有引用基类的地方必须能透明地使用其子类的对象。

在运用里氏替换原则时,应该将父类设计为抽象类或接口,让子类继承父类或实现父类接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,可以很方便的扩展系统的功能,无需修改原有子类的代码。新增的功能可以通过增加一个新的子类来实现。

里氏替换原则很好的说明了 Java 多态的特征。

依赖倒置原则

依赖倒置原则指代了一种特定的解耦形式,使得高层次的模块不依赖于低层次的模块的实现细节的目的,依赖模块被颠倒了。
依赖倒置原则有以下几个关键点:
(1)高层模块不应该依赖低层模块,两者都应该依赖其抽象;
(2)抽象不应该依赖细节;
(3)细节应该依赖抽象。
总的来说,就是要面向接口编程。
为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明够的方法,不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

大多数情况下,开闭原则、里氏替换原则、依赖倒置原则 这三个设计原则会同时出现,开闭原则是目标,里氏替换原则是基础,依赖倒置原则是手段,它们相辅相成,相互补充,目标一致,只是分析问题是所站角度不同而已。

接口隔离原则

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
image.pngimage.png
上面两个图中是接口拆分前后的对比。如果不拆分,猫、狗、鸟都实现 IAnimal 这个接口时,都要实现不必要的方法,例如对于猫狗来说,飞翔和滑翔方法就是不必要的。拆分后,可以根据需求来实现自己需要的功能。

在使用接口隔离原则是要注意控制接口的粒度,太小会导致接口的泛滥,太大也会违背接口隔离原则,灵活性较差,使用起来不方便。

合成复用原则

尽量使用对象组合,而不是继承来达到复用的目的。
通过继承进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,这种复用又称为“白箱”复用,如果基类发生改变那么子类的实现也不得不发生改变。
使用组合或聚合关系将已有对象纳入到新对象中,使之成为新对象的一部分。因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,这种复用又称为“黑箱”复用。
相对继承而言,这种复用耦合性不大,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性的调用成员对象的操作。

迪米特原则

如果两个类不必彼此通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
外观模式(Facade Pattern)和中介者模式(Mediator Pattern)就使用了迪米特法则。
迪米特法则首先强调的前提是在类的结构设计上,每一个类都应当尽量降低成员的访问权限。也就是说每一个类包装好自己的private 状态,不需要让别的类知道的字段或者行为就不要公开。

迪米特法则根本思想,是强调了类之间的松耦合。

我们在设计程序时,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
迪米法则还有几种定义形式:不要和“陌生人”说话,只与你的直接朋友通信等。在迪米特法则中,对于一个对象,其“朋友”包括以下几类:

  1. 当前对象本身(this)。
  2. 以参数形式传入到当前对象方法中的对象。
  3. 当前对象的成员变量。
  4. 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友。
  5. 当前对象所创建的对象。

一个对象应该对其他对象有最少的了解。通俗地讲, 一个类应该对自己需要耦合或调用的类知道得最少,类的内部如何实 现与调用者或者依赖者没关系,调用者或者依赖者只需要知道它需要 的方法即可,其他的可一概不用管。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

例如:租客租房,只与中介者进行直接交互。
image.png