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