繼承有什么好處?最大的好處是子類獲得了父類的全部功能徒河。由于Animial實現(xiàn)了run()方法多律,因此痴突,Dog和Cat作為它的子類,什么事也沒干狼荞,就自動擁有了run()方法
當子類和父類都存在相同的run()方法時辽装,我們說,子類的run()覆蓋了父類的run()相味,在代碼運行的時候拾积,總是會調用子類的run()。這樣,我們就獲得了繼承的另一個好處:多態(tài)拓巧。
當我們定義一個class的時候斯碌,我們實際上就定義了一種數(shù)據(jù)類型。我們定義的數(shù)據(jù)類型和Python自帶的數(shù)據(jù)類型肛度,比如str傻唾、list、dict沒什么兩樣. 在繼承關系中承耿,如果一個實例的數(shù)據(jù)類型是某個子類冠骄,那它的數(shù)據(jù)類型也可以被看做是父類
多態(tài)的好處就是,當我們需要傳入Dog瘩绒、Cat猴抹、Tortoise……時,我們只需要接收Animal類型就可以了锁荔,因為Dog蟀给、Cat、Tortoise……都是Animal類型阳堕,然后跋理,按照Animal類型進行操作即可。由于Animal類型有run()方法恬总,因此前普,傳入的任意類型,只要是Animal類或者子類壹堰,就會自動調用實際類型的run()方法拭卿,這就是多態(tài)的意思
對于一個變量,我們只需要知道它是Animal類型贱纠,無需確切地知道它的子類型峻厚,就可以放心地調用run()方法,而具體調用的run()方法是作用在Animal谆焊、Dog惠桃、Cat還是Tortoise對象上,由運行時該對象的確切類型決定辖试,這就是多態(tài)真正的威力:調用方只管調用辜王,不管細節(jié),而當我們新增一種Animal的子類時罐孝,只要確保run()方法編寫正確呐馆,不用管原來的代碼是如何調用的。這就是著名的“開閉”原則:
對擴展開放:允許新增Animal子類莲兢;
對修改封閉:不需要修改依賴Animal類型的函數(shù)摹恰。
靜態(tài)語言 vs 動態(tài)語言
對于靜態(tài)語言(例如Java)來說辫继,如果需要傳入Animal類型,則傳入的對象必須是Animal類型或者它的子類俗慈,否則,將無法調用run()方法遣耍。
對于Python這樣的動態(tài)語言來說闺阱,則不一定需要傳入Animal類型。我們只需要保證傳入的對象有一個run()方法就可以了:
class Timer(object): def run(self): print('Start...')
這就是動態(tài)語言的“鴨子類型”舵变,它并不要求嚴格的繼承體系酣溃,一個對象只要“看起來像鴨子,走起路來像鴨子”纪隙,那它就可以被看做是鴨子赊豌。
動態(tài)語言的鴨子類型特點決定了繼承不像靜態(tài)語言那樣是必須的。