上一节课我们说完了继承,那这节课我们就继续深入,来看看继承树的大招是什么。
可能我和你说起多态这个发音,你最先想到的应该是高中生物里讲的“多肽”;好吧,这两者之间唯一相同的可能就是发音了。
继承的意义
我们说继承实现的意义非凡,它大大降低了我们代码中的冗余行数,降低了代码的维护难度……
其实,我没有提到继承的另一个意义——合约。
上一节课我们做了演示,继承代表了子类获得了父类所有可继承的属性和方法——换句话说,我们也可以这样理解:继承确保了子类拥有父类的全部可继承属性和方法。
你看,我们写了一个具有这样那样成员的“武器”类,那么武器下所有子类都一定会具有“武器”类的属性和方法——即使方法被重写了——没关系,但这个方法还是存在的。
回到遥控器和电视机的梗上
也就是说,不论这个电视机如何进化,我的新一代遥控器上永远都拥有最初的那几个功能按钮。
我们声明一个储存器,然后放到里边的不是值,而是引用——这个引用也有类型,它包含了引用的对象的属性和方法……的按钮。所以我们无法再把它指向另一个完全不同的对象而只能指向相同的一类对象。
但是我们了解了继承,那就有了一个问题产生——旧遥控器上的按钮似乎也能对新一代的电视机生效。
没错!这就是多态!
我们创建一个储存器,把类型指定为某一个类的引用,但如果我们指向的是这个类的子类——没错,可以通过编译!这是允许的!
这样,我们就可以储存多种状态了!——这就是
多态
那么……我们来举个栗子吧!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Weapon { func fire() { } } class Gun:Weapon { override func fire() { print("bang!") } } class MachineGun:Weapon { override func fire() { print("dadadada!") } } var weapons:[Weapon] = [] let gun = Gun() let machineGun = MachineGun() weapons = [gun,machineGun] for guns in weapons { guns.fire() } |
我们声明是数组 weapons 虽然是 Weapon 的数组类型,但实际上放进去的却都是 Weapon 的不同子类。
我们遍历数组,执行子类里边的 fire() 方法,得到的结果也不同。我们说这里的子类是 Weapon 类的不同状态。 —— 故称多态。
现在,我们试试看利用多态把对象当做参数传来传去:
1 2 3 4 5 6 7 |
func fireThem(g:Weapon) { g.fire() } fireThem(gun) fireThem(machineGun) |
你看,我们把子类传进去……就好像这些子类都应用了同一个“合约”,我们只需要按照这个“合约”操作,那么不用关心传进来的子类究竟如何实现了这个方法,反正他们必须得有这个方法就对了。
总结
没错,声明为父类的储存器可以引用所有对应的子类!
这就是多态机制。透过这个机制,我们可以达成更高的协作水准。作为一个程序的源代码,总要有人实现上层建筑有人实现底层基础……现在有了多态,我们设计软件结构初期规定好了继承树,那么上层和下层不需要时间上的等待和延迟,可以同时进行了——它们不再相关,各自的升级也不需要互相影响——因为我们有“合约”,调用者只要调用父类就好了!
转载请保留出处和原文链接:https://www.logcg.com/archives/1121.html
Comments