Go 中没有提供继承的语义, 可以使用组合设计模式, 只需简单的将一个类型嵌入另一个类型就能实现复用 (组合 VS 继承, 而且继承是静态的, 在写代码时就已经决定子类的上级, 而组合相对来说是动态的, 要到了运行时才知道到底组合了哪个部分类, 因为组合实际上是对象模型, 而非类模型).
Go 对组合模式进行了优化, 提供了匿名组合, 让组合类可以直接”点”出部分类的方法 (具体看下面的实践).
本次实践体现了面向对象的三个原则:
- 优先使用组合 (而非继承)
- 针对接口编程
- 延迟设计
假设现在存在一个车类 (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() }
☠