1. 程式人生 > >Python設計模式 - 基礎 - 類與類之間的六種關系

Python設計模式 - 基礎 - 類與類之間的六種關系

eth abc plane running 創建 ima 程序 art []

在程序中需要把世間萬物抽象成相應的類,現實世界中物與物之間的關系和程序中類與類之間的關系相對應,因為世間萬物是普遍聯系的,所以程序中類與類之間也不是孤立的。在系統分析和框架設計中,根據面向對象機制的三大特性:封裝、繼承、多態,歸納和擴展出類與類之間六種不同的關系:

    - 依賴關系Dependency: 在局部變量,方法的形參,或者對靜態方法的調用中實現

    - 關聯關系Association: 在類的成員變量中實現,可以雙向也可以單向

    - 聚合關系Aggregation: 強關聯,整體與部分的關系,但是可分離

    - 組合關系Composition: 更強關聯,整體與部分的關系,不可分離

    - 繼承關系Generalization:類與類,或接口與接口之間的父子關系

    - 實現關系Implementation: 接口或抽象類定義好的操作集合,由實現類完成接口或抽象類的具體操作

其實從更寬泛的角度來說,類與類之間的關系其實只有三種:繼承、實現、關聯(依賴是一種弱關聯,聚合和組合是關聯中的特例)。繼承和實現是類與類之間的縱向關系,比如A類繼承了B類,C類實現了D接口;而關聯是類與類之間的橫向關系,類與類之間的關聯關系從弱到強依次為:依賴 < 關聯 < 聚合 < 組合。

縱向的繼承和實現關系很容易理解,橫向的關聯關系相對復雜些,尤其是對生命周期的不同處理,關聯、聚合、組合只能結合上下文語義才好判斷。下面就重點介紹下這些容易相互混淆的關聯關系。

依賴關系(Dependency)

概念說明

可以簡單地理解,依賴就是一個類A使用到了另一個類B,僅僅是“使用到”,類B本身並不屬於類A,或者說類A並不擁有類B。依賴關系是偶然性的、臨時性的,但是因為類B本身被類A引用到,所以B類的變化也會影響到類A。比較常見的場景就是人乘飛機從一地到另一地,飛機和人之間並沒有所屬關系,只是一種臨時性的出行工具,此時人和飛機之間就是依賴關系。

代碼實現

依賴關系在代碼上體現為三種形式:

    - 類B作為類A方法的形參

    - 類B作為類A方法的局部變量

    - 類A調用類B的靜態方法

# 類B作為類A方法的形參

class Person(object):
    def flying(self, plane):
        plane.fly()
        
class Plane(object):
    def fly(self):
        print ("The plane is flying.")

>>> person = Person()
>>> plane = Plane()
>>> person.flying(plane)
The plane is flying.
>>> 

# 類B作為類A方法的局部變量

class Person(object):
    def flying(self):
        self.plane = Plane()
        plane.fly()

        
class Plane(object):
    def fly(self):
        print ("The plane is flying")

        
>>> person = Person()
>>> person.flying()
The plane is flying.
>>> 

# 類A調用類B的靜態方法

class Person(object):
    def flying(self):
        Plane.fly()

        
class Plane(object):
    @staticmethod
    def fly():
        print ("The plane is flying.")

        
>>> person = Person()
>>> person.flying()
The plane is flying.
>>>

UML類圖

UML中使用帶箭頭的虛線表示,箭頭指向表示調用關系,從類A指向類B

技術分享圖片

關聯關系(Association)

概念說明

關聯關系一般長期性的、擁有性的關系,而且雙方的關系一般是平等的,如學校與學生之間、老師與學生之間。被關聯類B以類的屬性形式出現在關聯類A中,關聯可以是單向的,也可以是雙向的。

依賴關系與關聯關系的區別有動靜之分,依賴關系的偶然性和臨時性說明了動態性,關聯關系的長期性、擁有性靜態地展示了對被關聯類的引用。

代碼實現

關聯關系在代碼上體現為二種形式:

    - 單向關聯:單向擁有關系,只有一個類知道另一個類的屬性和方法

    - 雙向關聯:雙向擁有關系,雙方都知道對方的屬性和方法

    - 自身關聯:自己關聯自己,這種情況比較少但也有用到,如鏈表

# 單向關聯
class Student(object): def __init__(self): self.title = "Seno"
def study(self): print ("Studying...") class School(object): def __init__(self): self.address = "ABC Street" self.student = Student() def act(self): print (self.student.title) self.student.study() >>> school = School() >>> school.act() Seno Studying... >>>

# 雙向關聯

class
Student(object): def __init__(self): self.school = School() class School(object): def __init__(self): self.student = Student()

    

# 自身關聯

class Node(object):
    def __init__(self):
        self.next = Node()

UML類圖

UML中使用直線箭頭表示,箭頭指向為被關聯的類,從類A指向類B

單向關聯

技術分享圖片

雙向關聯

技術分享圖片

自我關聯

技術分享圖片

聚合關系(Aggregation)

概念說明

聚合關系是也是關聯關系的特例。普通關聯關系的兩個類一般處於同一平等層次上,而聚合關系的兩個類處於不同的層次,是整體與部分的關系。聚合關系中的整體和部分是可以分離的,生命周期也是相互獨立的,如公司與員工之間。

代碼實現

聚合關系在代碼上體現為:類A由類B聚合而成,類A包含有類B的全局對象,但類B的對象可以不在類A創建的時刻創建。

class School(object):
    def __init__(self):
        self.__students = []

    def add_student(self, student):
        self.__students.append(student)


class Student(object):
    pass

>>> student = Student()
>>> school = School()
>>> school.add_student(student)
>>> 

UML類圖

UML中使用空心菱形+實線箭頭表示,空心菱形邊指向類A(整體),實現箭頭邊指向部分類B(部分)

技術分享圖片

組合關系(Composition)

概念說明

組合關系也是關聯關系的特例,屬於強聚合,本身也表示整體與部分的關系,但是組合關系中的整體和部分是不可分離的,整體生命周期的結束時也是部分的生命周期到頭時。如人和大腦。

聚合和組合其實都是關聯的特例,都是整體與部分的關系。它們的區別在於整體和部分是否可分離,聚合的兩個對象之間是可分離的,且具有各自的生命周期,而組合的兩個對象往往表現為一種同命相連的關系。

代碼實現

組合關系在代碼上體現為在整體類的構造方法中直接實例化成員類,因為類組合關系中整體與部分是共生的。

class Person(object):
    def __init__(self):
        print ("Person Iinitialization Start")
        self.__brain = Brain()
        print ("Person Iinitialization End")

    def run(self):
        print ("Running...")

class Brain(object):
    def __init__(self):
        print ("Brain Initialization Start")
        print ("Brain Initialization End")


>>> person = Person()
Person Iinitialization Start
Brain Initialization Start
Brain Initialization End
Person Iinitialization End
>>> person.run()
Running...
>>> 

UML類圖

UML中使用實心菱形+實線箭頭表示,實心菱形邊指向類A(整體),實線箭頭邊指向類B(部分)

技術分享圖片

繼承關系(Generalization)

概念說明

繼承指的是子類繼承父類、或子接口繼承父接口的功能並增加自己新功能的過程,是兩個類之間耦合度最大的關系之一。父類稱為基類或超類,子類也稱為派生類。子類可以繼承自抽象類或普通類。

代碼實現

繼承關系在代碼上體現為二種形式:

    - 子類繼承自抽象類或普通類

    - 子接口繼承自父接口:適用於Java


# 子類繼承自抽象類,必須實現父類中@abstractmethod修飾的抽象方法
from abc import ABCMeta, abstractmethod

class
Animal(metaclass=ABCMeta): def __init__(self): self.name = "Animal" @abstractmethod def run(self): print ("Animal is running.") def play(self): print ("Animal is playing.") class Dog(Animal): def __init__(self): self.name = "Dog" def run(self): print ("Dog is running.") def __bark(self): print ("Dog is barking.") class Cat(Animal): def __init__(self): self.name = "Cat" def run(self): print ("Animal is running.") def play(self): print ("Cat is running.") def __jump(self): print ("Cat is jumping.") >>> dog = Dog() >>> cat = Cat() >>> dog.run() Dog is running. >>> dog.play() Animal is playing.>>> cat.run() Animal is running. >>> cat.play() Cat is running.>>>

# 子類繼承自普通類,子類方法重寫父類同名非私有方法

class Animal(object): def __init__(self): self.name = "Animal" def run(self): print ("Animal is running.") def play(self): print ("Animal is playing.") class Dog(Animal): def __init__(self): self.name = "Dog" def run(self): print ("Dog is running.") def __bark(self): print ("Dog is barking.") class Cat(Animal): def __init__(self): self.name = "Cat" def play(self): print ("Cat is running.") def __jump(self): print ("Cat is jumping.") >>> dog = Dog() >>> cat = Cat() >>> dog.run() Dog is running. >>> dog.play() Animal is playing.>>> cat.run() Animal is running. >>> cat.play() Cat is running.>>>

UML類圖

UML中使用實線+空心箭頭表示,箭頭由子類指向父類、或子接口指向父接口

技術分享圖片

實現關系(Implementation)

概念說明

實現關系是指一個類實現一個或多個接口功能的過程,這裏的接口更多的是一種契約或規範。實現是兩個類之間或類與接口之間耦合度最大的關系之一,在這種關系中,類實現了接口或接口類中所聲明的操作。


代碼實現

實現關系在代碼上體現為二種形式:

    - 類具體實現接口中所聲明的操作:如Java中支持原生interface,可以直接implement

    - 類具體實現接口類中所聲明的操作:如python中無原生interface,這裏的接口類更多的是邏輯上的契約或規範

class Car(object):
    def engine(self):
        raise NotImplementedError

class Benz(Car):
    def engine(self):
        print ("Benz is running.")

        
class BMW(Car):
    def engine(self):
        print ("BMW is running.")

        
>>> benz = Benz()
>>> bmw = BMW()
>>> benz.engine()
Benz is running.
>>> bmw.engine()
BMW is running.
>>> 

UML類圖

UML中使用虛線+空心箭頭表示,箭頭由實現類指向接口

技術分享圖片

Python設計模式 - 基礎 - 類與類之間的六種關系