单一职责原则(Single Responsibility Principle, SRP)

类的职责单一,对外只提供一种功能,而引起类变化的原因都应该只有一个。

开闭原则(Open-Closed Principle, OCP)

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

类的改动是通过增加代码进行的,通过扩展来实现变化,而不是修改源代码。

里氏代换原则(Liskov Substitution Principle, LSP)

炫杉:由 Go 实现。定义的接口,可以传入任何实现了该接口的结构体。

任何抽象类(interface接口)出现的地方都可以用他的实现类进行替换,实际就是虚拟机制,语言级别实现面向对象功能。

依赖倒转原则(Dependence Inversion Principle, DIP)

炫杉:先设计规约 -> 再实现规约

依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。

接口隔离原则(Interface Segregation Principle, ISP

不应该强迫用户的程序依赖他们不需要的接口方法。

一个接口应该只提供一种对外功能,不应该把所有操作都封装到一个接口中去。

合成复用原则(Composite Reuse Principle, CRP)

如果使用继承,会导致父类的任何变换都可能影响到子类的行为。

如果使用对象组合,就降低了这种依赖关系。对于继承和组合,优先使用组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import "fmt"

type Cat struct {}

func (c *Cat) Eat() {
fmt.Println("小猫吃饭")
}

//给小猫添加一个 可以睡觉的方法 (使用继承来实现)
type CatB struct {
Cat
}

func (cb *CatB) Sleep() {
fmt.Println("小猫睡觉")
}

//给小猫添加一个 可以睡觉的方法 (使用组合的方式)
type CatC struct {
C *Cat
}

func (cc *CatC) Sleep() {
fmt.Println("小猫睡觉")
}


func main() {
//通过继承增加的功能,可以正常使用
cb := new(CatB)
cb.Eat()
cb.Sleep()

//通过组合增加的功能,可以正常使用
cc := new(CatC)
cc.C = new(Cat)
cc.C.Eat()
cc.Sleep()
}

这个例子里。CatB的实现,是继承了 Cat,但是实际上,如果 CatB 只是想用 Cat 的一个 Eat 能力,如果 Cat 还有其他 99 种能力,CatB 就无形地把它的 100 种能力都继承了。

而 CatC 的写法就解耦了。其他的能力都在 CatC 的成员 C 身上,而不再 CatC 这整个类上。

迪米特法则(Law of Demeter, LoD

知道最少法则

一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的可维护性。

炫杉:类比防腐层

例如在一个程序中,各个模块之间相互调用时,通常会提供一个统一的接口来实现。这样其他模块不需要了解另外一个模块的内部实现细节,这样当一个模块内部的实现发生改变时,不会影响其他模块的使用。(黑盒原理)