大白话解读:Golang接口、多态和继承教程-31

发表时间: 2023-02-03 20:48

接口 interface 规定了具备某种行为能力的对象,为了系统更容易扩展和维护,常常需要面向接口编程,接口是抽象的一种表达形式。比如作为 Animal 动物这个抽象类型,应该有吃饭和睡觉的行为,同时都作为宠物的属性都能和人一起玩耍,没问题吧?

type Animal interface {  eat(food string)   sleep(hours uint)  playAsPet()       }

如果一个对象拥有了接口所定义的行为,那么就说这个对象实现了该接口,也可以安全的转换为对应的接口对象。比如猫和狗都具备了 Animal 的行为,它们就可以被安全的转换为 Animal 这个类型。

// 猫type Cat struct {}func (cat *Cat) eat(food string) {...}func (cat *Cat) sleep(hours uint) {...}func (cat *Cat) playAsPet() {...}// 狗type Dog struct {}func (dog *Dog) eat(food string) {...}func (dog *Dog) sleep(hours uint) {...}func (dog *Dog) playAsPet() {...}

为什么猫和狗不直接使用 Animal 来表达呢? 因为猫和狗虽然具备了一些相同的行为,并同时也具备了很多不同的行为,当你想收拾一只老鼠的时候,肯定是派一只猫去更合适,对吧(有人不这么想)? 当你想留一个看家的时候,肯定是狗要合适些,对吧?

// 猫捉老鼠func (cat *Cat) catchMouse() {...}// 狗来看家func (dog *Dog) defendHouse() {...}

可见接口用来抽象共同的行为,当你寂寞想找个宠物放松一下时,去找 cat 和 dog 都可以满足你,但当你需要捉老鼠或者看家的时候,你就不能随便选一个了。

回到 playAsPet() 上来,很显然和猫玩耍的方式与狗不同,猫可能喜欢陪你在家看书,而狗更合适陪你去户外遛弯,虽然都能陪你打发时间,但是你的体验会不一样,这就是多态! 来看看多态教科书的表达: 多态是同一个行为(playAsPet)具有多个不同表现形式或形态的能力(看书、遛弯);多态就是同一个接口(Animal),使用不同的实例(Cat、Dog)而执行不同操作(catchMouse、defendHouse)。

那么继承又有什么用呢? 拿 Dog 来举例子,狗还有很多种,对吧? 比如警犬,不仅能吃、能睡、陪你玩,还能帮你抓到犯罪嫌疑人,当你的系统要表达一只警犬的时候,你不想把 eat、sleep、playAsPet 重新都写一遍对吧? 如果你想对 playAsPet 方法做一些修改,作为宠物来讲,它也应该同时被修改对吧? 所以最好的方式就是继承 Animal 的行为,定一个能辅助警察工作的类型,而警犬是其中一个特例,比如它可能是德国牧羊犬,有可能是昆明犬,对吧?

// 能帮警察搞事情的动物type PoliceAnimal interface {  Animal           arrestBadMan()}// 牧羊犬type HuntawayDog struct {  Dog}func (huntawayDog *HuntawayDog) arrestBadMan() {...}

你现在想让 HuntawayDog 或者 KunmingDog 陪你散散步,是没有问题,对吧? 所以你现在可以一个能吃、能睡、能陪你玩,还能抓捕坏人的朋友,你可能需要的是 PoliceAnimal,当你真的要执行抓捕任务的时候,不管是 HuntawayDog 还是 KunMingDog,都能完成任务。

func atPeace(animal Animal) {  animal.eat("meat")  animal.sleep(10)  animal.playAsPet()}func doTask(animal PoliceAnimal) {  animal.arrestBadMan()}func main() {  huntawayDog := &HuntawayDog{}  atPeace(huntawayDog)   doTask(huntawayDog)}

不同的语言对接口、多态、集成的支持力度不同,但核心思想如此,剩下的只是语法的表达。

源代码参考
https://github.com/developdeveloper/go-demo/tree/master/30-oop-aifb/02-oop

S.O.L.I.D Design - oop 经典设计原则

  • SRP 单一职责
  • OCP 开闭原则
  • LSP 里氏替换
  • DIP 依赖反转
  • LKP 最少知识

https://github.com/developdeveloper/go-demo/tree/master/31-solid-design