1. 程式人生 > >面向物件:類空間問題以及類之間的關係

面向物件:類空間問題以及類之間的關係

一. 類的空間問題

1.1 何處可以新增物件屬性

class A:
    def __init__(self,name):
        self.name = name

    def func(self,sex):
        self.sex = sex
# 類外面可以:
obj = A('barry')
obj.age = 18
print(obj.__dict__)  # {'name': 'barry', 'age': 18}

# 類內部也可以:
obj = A('barry') # __init__方法可以。
obj.func('男')  # func 方法也可以。

**總結:物件的屬性不僅可以在__init__裡面新增,還可以在類的其他方法或者類的外面新增。**

1.2 何處可以新增類的靜態屬性

class A:
    def __init__(self,name):
        self.name = name

    def func(self,sex):
        self.sex = sex
    
    def func1(self):
        A.bbb = 'ccc'
# 類的外部可以新增

A.aaa = 'taibai'
print(A.__dict__)

# 類的內部也可以新增。

A.func1(111)
print(A.__dict__)

總結:類的屬性不僅可以在類內部新增,還可以在類的外部新增。

1.3 物件如何找到類的屬性

之前咱們都學習過,例項化一個物件,可以通過點的方式找到類中的屬性,那麼他為什麼可以找到類中的屬性呢?

通過圖解說明:

物件查詢屬性的順序:先從物件空間找 ------> 類空間找 ------> 父類空間找 ------->.....

類名查詢屬性的順序:先從本類空間找 -------> 父類空間找--------> ........

上面的順序都是單向不可逆,類名不可能找到物件的屬性。

二. 類與類之間的關係

⼤千世界, 萬物之間皆有規則和規律. 我們的類和物件是對⼤千世界中的所有事物進⾏歸類. 那事物之間存在著相對應的關係. 類與類之間也同樣如此. 在⾯向物件的世界中. 類與類中存在以下關係:

\1. 依賴關係
\2. 關聯關係
\3. 組合關係
\4. 聚合關係
\5. 實現關係
\6. 繼承關係(類的三大特性之一:繼承。)

2.1 依賴關係

⾸先, 我們設計⼀個場景. 還是最初的那個例⼦. 要把⼤象裝冰箱. 注意. 在這個場景中, 其實是存在了兩種事物的. ⼀個是⼤象, ⼤象負責整個事件的掌控者, 還有⼀個是冰箱, 冰箱負責被⼤象操縱.

⾸先, 寫出兩個類, ⼀個是⼤象類, ⼀個是冰箱類

class Elphant:
    def __init__(self, name):
        self.name = name

    def open(self):
        '''
        開⻔
        '''
        pass
    
    def close(self):
        '''
        關⻔
        '''
        pass


class Refrigerator:
    
    def open_door(self):
        print("冰箱⻔被打開了")
    
    def close_door(self):
        print("冰箱⻔被關上了")

  冰箱的功能非常簡單, 只要會開⻔, 關⻔就⾏了. 但是⼤象就沒那麼簡單了. 想想. ⼤象開⻔和關⻔的時候是不是要先找個冰箱啊. 然後呢? 開啟冰箱⻔. 是不是開啟剛才找到的那個冰箱⻔. 然後裝⾃⼰. 最後呢? 關冰箱⻔, 注意, 關的是剛才那個冰箱吧. 也就是說. 開⻔和關⻔⽤的是同⼀個冰箱. 並且. ⼤象有更換冰箱的權利, 想進那個冰箱就進那個冰箱. 這時, ⼤象類和冰箱類的關係並沒有那麼的緊密. 因為⼤象可以指定任何⼀個冰箱. 接下來. 我們把程式碼完善⼀下.

class Elphant:
    def __init__(self, name):
        self.name = name

    def open(self,obj1):
        '''
        開⻔

        '''
        print('大象要開門了,默唸三聲,開')
        obj1.open_door()

    def close(self):
        '''
        關⻔
        '''
        print('大象要關門了,默唸三聲,關')


class Refrigerator:

    def open_door(self):
        print("冰箱⻔被打開了")

    def close_door(self):
        print("冰箱⻔被關上了")


elphant1 = Elphant('大象')
haier = Refrigerator()
elphant1.open(haier)

  動作發起的主體是大象,你們把關門這個練一下。依賴關係:將一個類的物件或者類名傳到另一個類的方法使用。此時, 我們說, ⼤象和冰箱之間就是依賴關係. 我⽤著你. 但是你不屬於我. 這種關係是最弱的.比如. 公司和僱員之間. 對於正式員⼯, 肯定要簽訂勞動合同. 還得⼩⼼伺候著. 但是如果是兼職. 那⽆所謂. 需要了你就來. 不需要你就可以拜拜了. 這⾥的兼職(臨時⼯) 就屬於依賴關係.我⽤你. 但是你不屬於我

2.2 關聯,聚合,組合關係

其實這三個在程式碼上寫法是⼀樣的. 但是, 從含義上是不⼀樣的.

\1. 關聯關係. 兩種事物必須是互相關聯的. 但是在某些特殊情況下是可以更改和更換的.

\2. 聚合關係. 屬於關聯關係中的⼀種特例. 側重點是xxx和xxx聚合成xxx. 各⾃有各⾃的宣告週期. 比如電腦. 電腦⾥有CPU, 硬碟, 記憶體等等. 電腦掛了. CPU還是好的. 還是完整的個體

\3. 組合關係. 屬於關聯關係中的⼀種特例. 寫法上差不多. 組合關係比聚合還要緊密. 比如⼈的⼤腦, ⼼髒, 各個器官. 這些器官組合成⼀個⼈. 這時. ⼈如果掛了. 其他的東⻄也跟著掛了

  先看關聯關係:

這個最簡單. 也是最常⽤的⼀種關係. 比如. ⼤家都有男女朋友. 男⼈關聯著女朋友. 女⼈關聯著男朋友. 這種關係可以是互相的, 也可以是單⽅⾯的.

class Boy:
    def __init__(self,name,girlFriend=None):
        self.name = name
        self.girlFriend = girlFriend

    def have_a_diner(self):
        if self.girlFriend:
            print('%s 和 %s 一起晚飯'%(self.name,self.girlFriend.name))
        else:
            print('單身狗,吃什麼飯')


class Girl:
    def __init__(self,name):
        self.name = name
b = Boy('日天')
b.have_a_diner() # 此時是單身狗

# 突然有一天,日天牛逼了
b.girlFriend = '如花'
b.have_a_diner()  #共進晚餐
# wusir 生下來就有女朋友 服不服
gg = Girl('小花')
bb = Boy('wusir', gg)
bb.have_a_diner()

# 結果嫌他有點娘,不硬,分了
bb.girlFriend = None
bb.have_a_diner()

注意. 此時Boy和Girl兩個類之間就是關聯關係. 兩個類的物件緊密練習著. 其中⼀個沒有了. 另⼀個就孤單的不得了. 關聯關係, 其實就是 我需要你. 你也屬於我. 這就是關聯關係. 像這樣的關係有很多很多. 比如. 學校和老師之間的關係.

# 老師屬於學校,必須有學校才可以工作
class School:

    def __init__(self,name,address):
        self.name = name
        self.address = address


class Teacher:

    def __init__(self,name,school):
        self.name = name
        self.school = school

s1 = School('北京校區','美麗的沙河')
s2 = School('上海校區','上海迪士尼旁邊')
s3 = School('深圳校區','南山區')

t1 = Teacher('武大',s1)
t2 = Teacher('海峰',s2)
t3 = Teacher('日天',s3)

print(t1.school.name)
print(t2.school.name)
print(t3.school.name)

但是學校也是依賴於老師的,所以老師學校應該互相依賴。

class School:

    def __init__(self,name,address):
        self.name = name
        self.address = address
        self.teacher_list = []

    def append_teacher(self,teacher):
        self.teacher_list.append(teacher)
        
class Teacher:

    def __init__(self,name,school):
        self.name = name
        self.school = school

s1 = School('北京校區','美麗的沙河')
s2 = School('上海校區','上海迪士尼旁邊')
s3 = School('深圳校區','南山區')

t1 = Teacher('武大',s1)
t2 = Teacher('海峰',s2)
t3 = Teacher('日天',s3)

s1.append_teacher(t1)
s1.append_teacher(t2)
s1.append_teacher(t3)

# print(s1.teacher_list)
# for teacher in s1.teacher_list:
#     print(teacher.name)

好了. 這就是關聯關係. 當我們在邏輯上出現了. 我需要你. 你還得屬於我. 這種邏輯 就是關聯關係. 那注意. 這種關係的緊密程度比上⾯的依賴關係要緊密的多. 為什麼呢? 想想吧

至於組合關係和聚合關係,其實程式碼上差別不大,咱們就以組合舉例:

組合:將一個類的物件封裝到另一個類的物件的屬性中,就叫組合。

咱們設計一個遊戲人物類,讓例項化幾個物件讓這幾個遊戲人物實現互毆的效果。

class Gamerole:
    def __init__(self,name,ad,hp):
        self.name = name
        self.ad = ad
        self.hp = hp
    def attack(self,p1):
        p1.hp -= self.ad
        print('%s攻擊%s,%s掉了%s血,還剩%s血'%(self.name,p1.name,p1.name,self.ad,p1.hp))
gailun = Gamerole('蓋倫',10,200)
yasuo= Gamerole('亞索',50,80)

#蓋倫攻擊亞索
gailun.attack(yasuo)
# 亞索攻擊蓋倫
yasuo.attack(蓋倫)

但是這樣互相攻擊沒有意思,一般遊戲類的的對戰方式要藉助武器,武器是一個類,武器類包含的物件很多:刀槍棍劍斧鉞鉤叉等等,所以咱們要寫一個武器類。

class Gamerole:
    def __init__(self,name,ad,hp):
        self.name = name
        self.ad = ad
        self.hp = hp
    def attack(self,p1):
        p1.hp -= self.ad
        print('%s攻擊%s,%s掉了%s血,還剩%s血'%(self.name,p1.name,p1.name,self.ad,p1.hp))

class Weapon:
    def __init__(self,name,ad):
        self.name = name
        self.ad = ad
    def weapon_attack(self,p1,p2):
        p2.hp = p2.hp - self.ad - p1.ad
        print('%s 利用 %s 攻擊了%s,%s還剩%s血' %(p1.name,self.name,p2.name,p2.name,p2.hp))

接下來藉助武器攻擊對方:

pillow = Weapon('繡花枕頭',2)
pillow.weapon_attack(barry,panky)
# 但是上面這麼做不好,利用武器攻擊也是人類是動作的發起者,所以不能是pillow武器物件,而是人類利用武器攻擊對方

所以,對程式碼進行修改。

class Gamerole:
    def __init__(self,name,ad,hp):
        self.name = name
        self.ad = ad
        self.hp = hp
    def attack(self,p1):
        p1.hp -= self.ad
        print('%s攻擊%s,%s掉了%s血,還剩%s血'%(self.name,p1.name,p1.name,self.ad,p1.hp))
        
    def equip_weapon(self,wea):
        self.wea = wea  # 組合:給一個物件封裝一個屬性改屬性是另一個類的物件
class Weapon:
    def __init__(self,name,ad):
        self.name = name
        self.ad = ad
    def weapon_attack(self,p1,p2):
        p2.hp = p2.hp - self.ad - p1.ad
        print('%s 利用 %s 攻擊了%s,%s還剩%s血'
              %(p1.name,self.name,p2.name,p2.name,p2.hp))


# 例項化三個人物物件:
barry = Gamerole('太白',10,200)
panky = Gamerole('金蓮',20,50)
pillow = Weapon('繡花枕頭',2)

# 給人物裝備武器物件。
barry.equip_weapon(pillow)

# 開始攻擊
barry.wea.weapon_attack(barry,panky)

上面就是組合,只要是人物.equip_weapon這個方法,那麼人物就封裝了一個武器物件,再利用武器物件呼叫其類中的weapon_attack方法。

在python中類的實現關係和類的繼承是一個意