面向对象的S.O.L.I.D原则
Single responsibility principle
单一职责原则:改变类的原因不应该超过一个,即一个类应该只有一个职责。
实例:面积计算器
type AreaCalculate struct{}
func (a AreaCalculate) Calculate(p Plane) float64 {
return p.Area()
}
上述名为AreaCalculate
的类最好只进行一项功能:计算面积。而不是:
type AreaCalculate struct{}
func (a AreaCalculate) Calculate(p Plane) float64 {
return p.Area()
}
func (a AreaCalculate) PrintAreaAsJSON() {
// print as JSON
}
func (a AreaCalculate) PrintAreaAsXML() {
// print as XML
}
func (a AreaCalculate) PrintAreaAsStdin() {
// print as Stdin
}
错误示范:上述类不仅要计算面积,还有按照需求对面积进行相应的格式化输出,这就违反的了单一职责原则:一个类应该只有一个职责。正确的做法应该是再有另外一个类:对面积进行格式化(JSON、XML、Stdin等)输出。这样就有了两个类:计算面积的类,对计算出来的面积进行格式化打印的类。
Open-close principle
开放封闭原则:对象或者实体应该对扩展开放,对修改封闭。
Liskov substitution principle
里氏替换原则:任何子类或者派生类应该可以替换它的基类或者父类。
type Human struct {
skin string
gender string
height float64
}
func (h Human) Skin() string {
return h.skin
}
func (h Human) Gender() string {
return h.gender
}
func (h Human) Height() float64 {
return h.height
}
type Man struct {
Human
}
func (m Man) Skin() string {
return m.skin
}
func (m Man) Gender() string {
return "男"
}
func (m Man) Height() float64 {
return m.height
}
type Woman struct {
Human
}
func (w Woman) Skin() string {
return w.skin
}
func (w Woman) Gender() string {
return "女"
}
func (w Woman) Height() float64 {
return w.height
}
type Robot struct {
Human
}
如果你的设计将Robot
类继承了Human
类,这显然是不符合里氏替换原则的:因为Robot
类没有办法替换它的父类Human
。
Interface segregation principle
接口隔离原则:不应该强迫client实现它并不需要的接口。
Dependency inversion principle
依赖倒置原则:抽象不应该依赖于具体实现,具体实现应该依赖于抽象,即High-level的实体不应该依赖于Low-level的实体,也是依赖于抽象,而不依赖于具象。
比如在单一职责原则中提到的,面积计算器不应该依赖于具体的图形(Triangle或者Rectangle),而是依赖于抽象的图形(Plane)。因为抽象是具有具体图形的相同属性的集合,所以依赖于广泛的抽象,就能向下兼容具体的具象。