上一節課我們說完了繼承,那這節課我們就繼續深入,來看看繼承樹的大招是什麼。
可能我和你說起多態這個發音,你最先想到的應該是高中生物裡講的“多肽”;好吧,這兩者之間唯一相同的可能就是發音了。
繼承的意義
我們說繼承實現的意義非凡,它大大降低了我們代碼中的冗餘行數,降低了代碼的維護難度……
其實,我沒有提到繼承的另一個意義——合約。
上一節課我們做了演示,繼承代表了子類獲得了父類所有可繼承的屬性和方法——換句話說,我們也可以這樣理解:繼承確保了子類擁有父類的全部可繼承屬性和方法。
你看,我們寫了一個具有這樣那樣成員的“武器”類,那麼武器下所有子類都一定會具有“武器”類的屬性和方法——即使方法被重寫了——沒關係,但這個方法還是存在的。
回到遙控器和電視機的梗上
也就是說,不論這個電視機如何進化,我的新一代遙控器上永遠都擁有最初的那幾個功能按鈕。
我們聲明一個儲存器,然後放到裡邊的不是值,而是引用——這個引用也有類型,它包含了引用的對象的屬性和方法……的按鈕。所以我們無法再把它指向另一個完全不同的對象而只能指向相同的一類對象。
但是我們了解了繼承,那就有了一個問題產生——舊遙控器上的按鈕似乎也能對新一代的電視機生效。
沒錯!這就是多態!
我們創建一個儲存器,把類型指定為某一個類的引用,但如果我們指向的是這個類的子類——沒錯,可以通過編譯!這是允許的!
這樣,我們就可以儲存多種狀態了! ——這就是
多態
那麼……我們來舉個栗子吧!
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
註釋