类型嵌入实践

Par @Martin dans le
Tags :

Go 中没有提供继承的语义, 可以使用组合设计模式, 只需简单的将一个类型嵌入另一个类型就能实现复用 (组合 VS 继承, 而且继承是静态的, 在写代码时就已经决定子类的上级, 而组合相对来说是动态的, 要到了运行时才知道到底组合了哪个部分类, 因为组合实际上是对象模型, 而非类模型).

Go 对组合模式进行了优化, 提供了匿名组合, 让组合类可以直接”点”出部分类的方法 (具体看下面的实践).

本次实践体现了面向对象的三个原则:

  1. 优先使用组合 (而非继承)
  2. 针对接口编程
  3. 延迟设计

假设现在存在一个车类 (Car), 有一个开车方法 (Drive), 如下:

type Car struct {
}

func (car *Car) Drive() {
    log.Println("开车")
}

现在是没有接口的, “过多”或”太早”的设计都是没有意义的.

然后来了个新需求, 需要设计一个客车类 (PassengerCar), 分析发现 PassengerCar 也需要 Drive 方法, 可以与 Car 类复用, 此时可以考虑剥离接口了 (针对接口编程):

type Driver interface { // Go 推荐单一行为的接口, 可用 行为 + er 来命名
    Drive()
}

type PassengerCar struct { // 针对接口编程, 而不是对象, 即应该依赖接口
    Driver
}

func (pcar *PassengerCar) TransportPassengers() {
    log.Println("运输乘客")
}

func main() {
    pcar := PassengerCar{new(Car)}
    pcar.Drive()
    pcar.TransportPassengers()
}