面向對象程序設計最主要的有三個特征:封裝、繼承、多態(tài)
本節(jié)內(nèi)容主要講解面向對象的第一個特征:多態(tài)
1 多態(tài)的意義
多態(tài)是讓我們的程序在運行的過程中,在不同的狀態(tài)下進行動態(tài)的切換,實現(xiàn)復雜的功能為目的的一種程序開發(fā)手段
在之前的章節(jié)中,實現(xiàn)了類型的繼承關系之后,其實我們已經(jīng)見過多態(tài)的一種操作了:方法重寫實現(xiàn)的運行時多態(tài),對象在執(zhí)行具體的方法時,會直接執(zhí)行父類中繼承的對應的方法,如果該方法在子類中重寫了,就會執(zhí)行子類中重寫過的方法,實現(xiàn)的是一種運行過程中的多態(tài)處理,代碼如下:
# 定義父類
class Person(object):
def __init__(self, name):
self.__name = name
def playing(self):
print(self.__name + "正在游戲中...")
# 定義子類,繼承自Person
class Man(Person):
def __init__(self, name):
Person.__init__(self, name)
# 定義子類,繼承自Person
class Women(Person):
def __init__(self, name):
Person.__init__(self, name)
def playing(self):
print(self.__name + "正在游戲封裝找茬中...")
# 創(chuàng)建對象
man = Man("tom")
women = Women("jerry")
man.playing() # 子類中沒有重寫,直接執(zhí)行從父類繼承的playing()函數(shù)
women.playing() #子類中重寫了,直接執(zhí)行子類中的playing()函數(shù)
2. 多態(tài)的擴展
我們定義一個這樣的醫(yī)療系統(tǒng),所有的男人、女人、小孩等等都可以去醫(yī)院看病,然后康復的一個過程。
# 定義一個人的類型
class Person(object):
def __init__(self, name, age, gender):
self.__name = name
self.__age = age
self.gender = gender
def health(self):
print(self.__name + "康復了..")
# 定義醫(yī)院的類型
class Hospital(object):
# 定義一個治療的方法,可以給人治病
def care(self, person):
print("正在治病")
person.health()
# 定義男人類型,繼承自Person類型
class Man(Person):
def __init__(self, name, age):
Person.__init__(self, name, age, "男")
def health(self):
print(self.__name + "~介個男人康復了..")
# 定義女人類型,繼承自Person類型
class Women(Person):
def __init__(self, name, age):
Person.__init__(self, name, age, "男")
def health(self):
print(self.__name + "~介個男人康復了..")
# 創(chuàng)建人物對象
man = Man("小凡", 19)
women = Women("碧瑤",16)
# 創(chuàng)建醫(yī)院對象
h = Hospital()
# 治病救人
h.care(man) # 治療Man類型的對象
h.care(women) # 治療Women類型的對象
上面的代碼中,我們已經(jīng)可以看到,只要是從Person類型繼承過來的類型所創(chuàng)建的對象,都可以在醫(yī)院Hospital對象的care()中進行治療。已經(jīng)是一種多態(tài)。
同時如果功能需要擴展,需要多出來一個人物類型:小孩,小孩也會生病,也需要治療~此時對于功能的擴展非常簡潔,值需要添加如下代碼就可以搞定:
# 創(chuàng)建一個小孩類型,繼承自Person
class Children(Person):
def __init__(self, name):
Person.__init__(self, name)
# 創(chuàng)建具體的小孩對象
c = Children("小家伙")
h.care(c) # 執(zhí)行結果~小家伙康復了
可以看到這里擴展一個功能變得非常的簡單,對象和對象之間的協(xié)同關系由于繼承多態(tài)的存在讓功能的擴展實現(xiàn)起來比較快捷了。
2. 多態(tài)的完善
上面的代碼中,我們其實是存在一定的缺陷的
上述代碼設計的初衷是醫(yī)院對象可以治病救人,也就是Hosiptal對象的care()函數(shù)可以治療Person派生出來的對象。
但是從代碼邏輯中,我們可以看到只要傳遞給care()函數(shù)的參數(shù)對象中包含health()函數(shù)就可以進行處理,而并非必須是Person對象。
此時需要在函數(shù)中進行判斷處理,如果是Person對象就進行care()治療的處理,如果不是Person對象,就提示不做治療操作。
對象和類型的判斷可以通過isinstance(obj, Type)進行類型的判斷,如:
# 創(chuàng)建各種對象
lx = [1,2,3,4,5]
ld = {"1":"a", "2":"b"}
ls = {"1", "2", "3"}
man = Man("tom", 22)
women = Women("jerry", 21)
# isinstance(obj, Type)判斷是否屬于某種類型
isinstance(lx, list) # 執(zhí)行結果:True
isinstance(ld, dict) # 執(zhí)行結果:True
isinstance(ls, set) # 執(zhí)行結果:True
isinstance(man, Man) # 執(zhí)行結果:True
isinstance(women, Women) # 執(zhí)行結果:True
isinstance(man, Person) # 執(zhí)行結果:True
isinstance(women, Person) # 執(zhí)行結果:True
isinstance(women, list) # 執(zhí)行結果:False
上述代碼中,我們可以觀察到通過isinstance()函數(shù)進行變量所屬數(shù)據(jù)類型的判斷了,同時在繼承關系中,有一個情理之中的判斷結果:man是Man類型的,同時也是Person類型的,因為Man類型是從Person類型繼承過來的。
所以可以對之前的Hospital的care()函數(shù)進行如下改造:
# 改造Hospital對象
class Hospital(object):
# 改造care()函數(shù)進行處理
def care(person):
if isinstance(person, Person):
print("正在治療中...")
person.health()
else:
print("不是合適的對象")
此時如果再傳遞參數(shù),就要求必須是Person類型才可以進行治療
# 定義一個Animal類型
class Animal :
def __init__(self, name):
self.__name = name
def health(self):
print(self.__name + "正在康復中...")
# 創(chuàng)建對象
a = Animal("shuke")
# 治療
h.care(a)
# 執(zhí)行結果:不是合適的對象
