1. 程式人生 > >(十七)類與類之間的關係

(十七)類與類之間的關係

. 類與類之間的依賴關係

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

                 1. 依賴關係

                 2. 關聯關係

                 3. 組合關係

                 4. 聚合關係

                 5. 繼承關係

                 6. 實現關係

   先來看緊密程度最低的⼀個----依賴關係。假設要玩遊戲,那麼使用什麼呢?現在的方式挺多的,手機電腦,PS等,都可以,但是如果沒有這些工具,就玩不了這樣的遊戲,所以玩遊戲又得依賴這些工具,但是我可以選擇使用哪種工具,一種玩夠了,可以換別的工具繼續玩。看程式碼:

 

class Phone:
    def __init__(self):
        self.name = '手機'
class Computer:
    def __init__(self):
        self.name = '電腦'
class PS:
    def __init__(self):
        self.name = 'PS'
class Person:
    def play(self, type):
        print(f'使用{type.name}打遊戲')

phone = Phone()
computer = Computer()
ps = PS()
p = Person()
p.play(phone)
p.play(computer)
p.play(ps)

 

      可以看到,人玩遊戲時,是可以隨便更換工具的,所以這種依賴關係很不穩定,也就是緊密程度很低。

. 關聯關係.組合關係, 聚合關係

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

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

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

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

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

 

class Boy:
 	def __init__(self, name, girlFriend=None):
 		self.name = name
 		self.girlFriend = girlFriend
 	def have_a_dinner(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("jerry")
b.have_a_dinner()

# 突然⽜B了. 找到⼥朋友了
g = Girl("如花")
b.girlFriend = g # 有⼥朋友了
b.have_a_dinner()

gg = Girl("李⼩花")
bb = Boy("tom", gg) # 娃娃親. 出⽣就有⼥朋友. 服不服
bb.have_a_dinner() # 多麼幸福的⼀家
# 突然.bb失戀了. 娃娃親不跟他好了
bb.girlFriend = None
bb.have_a_dinner() # ⼜單身了

 

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

  School --- 學校

 Teacher--- 老師

老師必然屬於⼀個學校換句話說每個老師肯定有⼀個指定的⼯作機構就是學校那老師的屬性中必然關聯著學校

 

class School:
 	def __init__(self, name, address):
 		self.name = name
 		self.address = address
class Teacher:
 	def __init__(self, name, school=None):
 		self.name = name
 		self.school = school
s1 = School("北京大學", "地址111111")
s2 = School("清華大學", "地址222222")
s3 = School("哈佛大學", "地址333333")
t1 = Teacher("Tom", s1)
t2 = Teacher("Jerry", s1)
t3 = Teacher("Tony", s2)
t4 = Teacher("Peter", s3)

# 找到Peter所在的校區地址
print(t4.school.address)

 

  

想想這樣的關係如果反過來⼀個老師可以選⼀個學校任職那反過來⼀個學校有多少老師呢? ⼀堆吧? 這樣的關係如何來描述呢?

 

class School:
 	def __init__(self, name, address):
 		self.name = name
 		self.address = address
 		self.t_list = [] # 每個學校都應該有⼀個裝⼀堆⽼師的列表
 	def add_teacher(self, teacher):
 		self.t_list.append(teacher)
class Teacher:
 	def __init__(self, name, school=None):
 		self.name = name
 		self.school = school

s1 = School("北京大學", "地址111111")
s2 = School("清華大學", "地址222222")
s3 = School("哈佛大學", "地址333333")
t1 = Teacher("Tom", s1)
t2 = Teacher("Jerry", s1)
t3 = Teacher("Tony", s2)
t4 = Teacher("Peter", s3)
s1.add_teacher(t1)
s1.add_teacher(t2)
s1.add_teacher(t3)
# 檢視北京大學有哪些⽼師
for t in s1.t_list:
 	print(t.name)

 

   好了這就是關聯關係當我們在邏輯上出現了我需要你你還得屬於我這種邏輯就是關聯關係那注意這種關係的緊密程度比上⾯的依賴關係要緊密的多為什麼呢? 老師沒有學校,就不能教書了,學校沒有了老師,就沒有老師教學生了。兩者是互相需要的,學校需要老師,而且這個老師也是屬於這個學校的。開始的依賴關係中,我玩遊戲,不用手機,還可以使用其他的電腦或者PS等。

   ⾄於組合關係和聚合關係其實程式碼上的差別不⼤都是把另⼀個類的物件作為這個類的屬性來傳遞和儲存只是在含義上會有些許的不同⽽已

. 繼承關係.

      在⾯向物件的世界中存在著繼承關係我們現實中也存在著這樣的關係我們說過。 x是⼀y,x就可以繼承y,這是理解層⾯上的如果上升到程式碼層⾯我們可以這樣認為⼦類在不影響⽗類的程式運⾏的基礎上對⽗類進⾏的擴充和擴充套件這⾥我們可以把⽗類被稱為超類或者基類⼦類被稱為派⽣類

  ⾸先類名和物件預設是可以作為字典的key的。

class Foo:
 	def __init__(self):
 		pass
 	def method(self):
 		pass
 # __hash__ = None
print(hash(Foo))
print(hash(Foo()))
既然可以hash. 那就是說字典的key可以是物件或者類。雖然顯⽰的有點⼉詭異. 但是是可以⽤的。
dic = {}
dic[Foo] = 123
dic[Foo()] = 456
print(dic) # {<class '__main__.Foo'>: 123, <__main__.Foo object at 0x103491550>: 456}

 

  接下來我們來繼續研究繼承上的相關內容在此主要研究⼀下self,記住不管⽅法之間如何進⾏調⽤類與類之間是何關係預設的self都是訪問這個⽅法的物件

                                                                                      

 

   分析一下上面的程式碼:1號線表示初始化時,把值=123給了num2號線表示obj呼叫func1(),但是在類Foo中沒有這個方法,所以程式會去Foo的父類Base中查詢,OK,找到了,同時把obj傳遞給了self。在func1()裡列印完num的值後,又呼叫了func2(),誰呼叫的這個func2()呢?當然是self,這裡的self,又是func1()被呼叫時,傳遞進來的obj,也就是Foo的物件,所以,要找func2(),也得去Foo中找,這是就近原則,也就是3號線的方向,雖然這樣看起來是跑遠了,但是Python就是這樣規定的。很完美找到了,所以直接列印就好了。看看下面程式碼,自己玩玩吧。

 

class Base:
 	def __init__(self, num):
 		self.num = num
 	def func1(self):
 		print(self.num)
 		self.func2()
 	def func2(self):
 		print(111, self.num)
class Foo(Base):
 	def func2(self):
 		print(222, self.num)

lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
 	obj.func1() # 那筆來吧. 算好了,可以跑一遍,看看結果。

  

. 類中的特殊成員

     什麼是特殊成員呢? __init_()就是⼀個特殊的成員說⽩了帶雙下劃線的那些, 這些⽅法在特殊的場景的時候會被⾃動的執⾏比如

    1. 類名() 會⾃動執⾏__init__()

    2. 物件() 會⾃動執⾏__call__()

    3. 物件[key] 會⾃動執⾏__getitem__()

    4. 物件[key] = value 會⾃動執⾏__setitemm__()

    5. del 物件[key] 會⾃動執⾏ __delitem__()

    6. 物件+物件 會⾃動執⾏ __add__()

    7. with 物件 as 變數 會⾃動執⾏__enter__ __exit__

    8. 列印物件的時候 會⾃動執⾏ __str__

    9. ⼲掉可雜湊 __hash__ == None 物件就不可雜湊了.

 建立物件的真正步驟:

  ⾸先在執⾏類名()的時候系統會⾃動先執⾏__new__()來開闢記憶體此時新開闢出來的內存區域是空的緊隨其後, 系統⾃動調⽤__init__()來完成物件的初始化⼯作按照時間軸來算

   1. 載入類

   2. 開闢記憶體(__new__)

   3. 初始化(__init__)

   4. 使⽤物件呼叫變數或者方法