26. 企業級開發基礎7:物件導向特徵(多型)

大牧莫邪發表於2017-05-23

物件導向程式設計最主要的有三個特徵:封裝、繼承、多型

本節內容主要講解物件導向的第一個特徵:多型

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)
# 執行結果:不是合適的物件

```

相關文章