1. 程式人生 > 實用技巧 >《認識 UML 類關係——依賴、關聯、聚合、組合、泛化》

《認識 UML 類關係——依賴、關聯、聚合、組合、泛化》

認識 UML 類關係——依賴、關聯、聚合、組合、泛化

文章目錄

在學習面向物件設計時,類關係涉及依賴、關聯、聚合、組合和泛化這五種關係,耦合度依次遞增。關於耦合度,可以簡單地理解為當一個類發生變更時,對其他類造成的影響程度,影響越小則耦合度越弱,影響越大耦合度越強。

下面根據個人理解,嘗試講解這五種類關係。

1. 依賴(Dependency)

依賴關係使用虛線加箭頭表示,如下圖所示:

學生在學習生活中經常使用電腦,於是對電腦產生了依賴。依賴關係是五種關係中耦合最小的一種關係。類 A 要完成某個功能引用了類 B,則類 A 依賴類 B。依賴在程式碼中主要體現為類 A 的某個成員函式的返回值、形參、區域性變數或靜態方法的呼叫,則表示類 A 引用了類 B。以 Student 類和 Computer 類為例,用 C++ 語言編碼如下:

class Computer
{
public:
    static void start(){
        cout<<"電腦正在啟動"<<endl;
    } 
};
class Student { public: //返回值構成依賴 Computer& program(); //形參構成依賴 void program(Computer&); void playGame() { //區域性變數構成依賴 Computer* computer=new Computer; ... //靜態方法呼叫構成依賴 Computer::star(); } };

2. 關聯(Association)

關聯關係使用實線加箭頭表示,類之間的關係比依賴要強。學生與老師是關聯的,學生可以不用電腦,但是學生不能沒有老師。如下圖所示:

關聯與依賴的對比:
相似之處:
關聯暗示了依賴,二者都用來表示無法用聚合和組合表示的關係。

區別:
(1)發生依賴關係的兩個類都不會增加屬性。其中的一個類作為另一個類的方法的引數或者返回值,或者是某個方法的變數而已。

發生關聯關係的兩個類,類 A 成為類 B 的屬性,而屬性是一種更為緊密的耦合,更為長久的持有關係。 在程式碼中的表現如下:

class Teacher;
class Student{
public:
    Teacher teacher;  //成員變數
    void study();
}

(2)從關係的生命週期來看,依賴關係是僅當類的方法被呼叫時而產生,伴隨著方法的結束而結束關聯關係當類例項化的時候產生,當類物件銷燬的時候關係結束。相比依賴,關聯關係的生存期更長。

關聯關係有單向關聯、雙向關聯、自身關聯、多維關聯等等。其中後三個可以不加箭頭。
單向關聯:

雙向關聯:

自身關聯:

多維關聯:

3. 聚合(Aggregation)

聚合關係使用實線加空心菱形表示。聚合用來表示集體與個體之間的關聯關係。例如班級與學生之間存在聚合關係,類圖表示如下:

聚合關係在程式碼上與關聯關係表現一致,類 Student 將成為類 Classes 的成員變數。程式碼如下:

class Student;
class Classes{
public:
    Student* student; 
    Classes(Student* stu):student(stu){}
};

4. 組合(複合,Composition)

複合關係使用實線加實心菱形表示。組合又叫複合,用來表示個體與組成部分之間的關聯關係。例如學生與心臟之間存在複合關係,類圖表示如下:

組合關係在程式碼上與關聯關係表現一致,類 Heart 將成為類 Student 的成員變數。程式碼如下:

class Heart;
class Student
{
public:
    Heart* heart; 
    Student()
    {
        heart=new Heart;
    }
    ~Student()
    {
        delete heart;
    }
};

聚合與組合的對比:
(1)聚合關係沒有組合緊密。
學生不會因為班級的解散而無法存在,聚合關係的類具有不同的生命週期;而學生如果沒有心臟將無法存活,組合關係的類具有相同的生命週期。

這個從建構函式可以看出。聚合類的建構函式中包含另一個類的例項作為引數,因為建構函式中傳遞另一個類的例項,因此學生可以脫離班級體獨立存在。組合類的建構函式包含另一個類的例項化。因為在建構函式中進行例項化,因此兩者緊密耦合在一起,同生同滅,學生不能脫離心臟而存在。

(2)資訊的封裝性不同。
在聚合關係中,客戶端可以同時瞭解 Classes 類和 Student 類,因為他們是獨立的。

在組合關係中,客戶端只認識 Student 類,根本不知道 Heart 類的存在,因為心臟類被嚴密地封裝在學生類中。

理解聚合與複合的區別,主要在於聚合的成員可獨立,複合的成員必須依賴於整體才有意義。

5. 泛化(Generalization)

泛化是學術名稱,通俗來講,泛化指的是類與類之間的繼承關係和類與介面之間的實現關係。

繼承關係使用直線加空心三角形表示。類圖結構如下:


類介面的實現關係使用虛線加空心三角形表示。類圖結構如下:

6. 小結

依賴、關聯、聚合、組合與泛化代表類與類之間的耦合度依次遞增。依賴關係實際上是一種比較弱的關聯,聚合是一種比較強的關聯,組合是一種更強的關聯,泛化則是一種最強的關聯,所以籠統的來區分的話,實際上這五種關係都是關聯關係。

依賴關係比較好區分,它是耦合度最弱的一種,在編碼中表現為類成員函式的區域性變數、形參、返回值或對靜態方法的呼叫。關聯、聚合與組合在編碼形式上都以類成員變數的形式來表示,所以只給出一段程式碼我們很難判斷出是關聯、聚合還是組合關係,我們需要從上下文語境中來判別。關聯表示類之間存在聯絡,不存在集體與個體、個體與組成部分之間的關係。聚合表示類之間存在集體與個體的關係。組合表示個體與組成部分之間的關係。

依賴、關聯、聚合與組合是邏輯上的關聯,泛化是物理上的關聯。物理上的關聯指的是類體的耦合,所以類間耦合性最強。

參考文獻

[1]認識 UML 中類之間的依賴、關聯、聚合、組合、泛化的關係
[2]UML 類關係(依賴,關聯,聚合,組合的區別)
[3]談一談自己對依賴、關聯、聚合和組合之間區別的理解


UML 圖中類之間的關係: 依賴, 泛化, 關聯, 聚合, 組合

類與類圖

1) 類 (Class) 封裝了資料和行為,是面向物件的重要組成部分,它是具有相同屬性、操作、關係的物件集合的總稱。 2) 在系統中,每個類具有一定的職責,職責指的是類所擔任的任務,即類要完成什麼樣的功能,要承擔什麼樣的義務。一個類可以有多種職責,設計得好的類一般只有一種職責,在定義類的時候,將類的職責分解成為類的屬性和操作(即方法)。 3) 類的屬性即類的資料職責,類的操作即類的行為職責

一、依賴關係 (Dependence)

依賴關係(Dependence):假設A類的變化引起了B類的變化,則說名B類依賴於A類。

• 依賴關係 (Dependency)是一種使用關係,特定事物的改變有可能會影響到使用該事物的其他事物,在需要表示一個事物使用另一個事物時使用依賴關係。大多數情況下,依 賴關係體現在某個類的方法使用另一個類的物件作為引數。 • 在 UML 中,依賴關係用帶箭頭的虛線表示,由依賴的一方指向被依賴的一方。
public class Driver
{
    public void drive(Car car)
    {
        car.move();
    }
    ……
}
public class Car
{
    public void move()
    {
        ......
    }
    ……
}


依賴關係有如下三種情況:

1、A類是B類中的(某中方法的)區域性變數;

2、A類是B類方法當中的一個引數;

3、A類向B類傳送訊息,從而影響B類發生變化;

二、泛化關係(Generalization)

泛化關係(Generalization):A是B和C的父類,B,C具有公共類(父類)A,說明A是B,C的一般化(概括,也稱泛化)

• 泛化關係 (Generalization)也就是繼承關係,也稱為 “is-a-kind-of” 關係,泛化關係用於描述父類與子類之間的關係,父類又稱作基類或超類,子類又稱作派生類。在 UML 中,泛 化關係用帶空心三角形的直線來表示。 • 在程式碼實現時,使用面向物件的繼承機制來實現泛化關係,如在Java語言中使用extends關鍵字、在C++/C#中使用冒號 “:” 來實現。
public class Person 
{
    protected String name;
    protected int age;
    public void move() 
    {
        ……
    }
    public void say() 
   {
        ……
    }
}
public class Student extends Person 
{
    private String studentNo;
    public void study() 
    {
        ……
    }
}


在UML當中,對泛化關係有三個要求:

1、子類與父類應該完全一致,父類所具有的屬性、操作,子類應該都有;

2、子類中除了與父類一致的資訊以外,還包括額外的資訊;

3、可以使用父類的例項的地方,也可以使用子類的例項;

三、關聯關係(Association)

關聯關係(Association):類之間的聯絡,如客戶和訂單,每個訂單對應特定的客戶,每個客戶對應一些特定的訂單,再如籃球隊員與球隊之間的關聯(下圖所示)。


其中,關聯兩邊的"employee"和“employer”標示了兩者之間的關係,而數字表示兩者的關係的限制,是關聯兩者之間的多重性。通常有“*”(表示所有,不限),“1”(表示有且僅有一個),“0...”(表示0個或者多個),“0,1”(表示0個或者一個),“n...m”(表示n到m個都可以),“m...*”(表示至少m個)。 • 關聯關係 (Association)是類與類之間最常用的一種關係,它是一種結構化關係,用於表示一類物件與另一類物件之間有聯絡。 • 在UML類圖中,用實線連線有關聯的物件所對應的類,在使用Java、C#和C++等程式語言實現關聯關係時,通常將一個類的物件作為另一個類的屬性。 • 在使用類圖表示關聯關係時可以在關聯線上標註角色名。 1) 雙向關聯:預設情況下,關聯是雙向的。
public class Customer
{
    private Product[] products;
    ……
}
public class Product
{
    private Customer customer;
    ……
}


2 )單向關聯:類的關聯關係也可以是單向的,單向關聯用帶箭頭的實線表示.
public class Customer
{
    private Address address;
    ……
}
 
public class Address
{
    ……
}

3)自關聯:在系統中可能會存在一些類的屬性物件型別為該類本身,這種特殊的關聯關係稱為自關聯。
public class Node
{
    private Node subNode;
    ……
}


4)重數性關聯:重數性關聯關係又稱為多重性關聯關係(Multiplicity),表示一個類的物件與另一個類的物件連線的個數。在UML中多重性關係可以直接在關聯直線上增加一個數字表示與之對應的另一個類的物件的個數。

表示方式

多重性說明

1..1

表示另一個類的一個物件只與一個該類物件有關係

0..*

表示另一個類的一個物件與零個或多個該類物件有關係

1..*

表示另一個類的一個物件與一個或多個該類物件有關係

0..1

表示另一個類的一個物件沒有或只與一個該類物件有關係

m..n

表示另一個類的一個物件與最少 m、最多 n 個該類物件有關係 (m<=n)

public class Form
{
    private Button buttons[];
    ……
} 
public class Button
{
    …
}

四、聚合關係(Aggregation)

聚合關係(Aggregation):表示的是整體和部分的關係,整體與部分可以分開.

• 聚合關係 (Aggregation)表示一個整體與部分的關係。通常在定義一個整體類後,再去分析這個整體類的組成結構,從而找出一些成員類,該整體類和成員類之間就形成了聚合 關係。 • 在聚合關係中,成員類是整體類的一部分,即成員物件是整體物件的一部分,但是成員物件可以脫離整體物件獨立存在。在UML中,聚合關係用帶空心菱形的直線表示。
public class Car
{
    private Engine engine;
    public Car(Engine engine)
   {
        this.engine = engine;
    }
    
    public void setEngine(Engine engine)
    {
        this.engine = engine;
    }
    ……
}
public class Engine
{
    ……
}


如:電話機包括一個話筒

電腦包括鍵盤、顯示器,一臺電腦可以和多個鍵盤、多個顯示器搭配,確定鍵盤和顯示器是可以和主機分開的,主機可以選擇其他的鍵盤、顯示器組成電腦;


五、組合關係(Composition)

組合關係(Composition):也是整體與部分的關係,但是整體與部分不可以分開.

• 組合關係(Composition)也表示類之間整體和部分的關係,但是組合關係中部分和整體具有統一的生存期。一旦整體物件不存在,部分物件也將不存在,部分物件與整體物件之 間具有同生共死的關係。 • 在組合關係中,成員類是整體類的一部分,而且整體類可以控制成員類的生命週期,即成員類的存在依賴於整體類。在UML中,組合關係用帶實心菱形的直線表示。
public class Head
{
    private Mouth mouth;
    public Head()
    {
    mouth = new Mouth();
    }
    ……
}
 
public class Mouth
{
    ……
}


如:公司和部門,部門是部分,公司是整體,公司A的財務部不可能和公司B的財務部對換,就是說,公司A不能和自己的財務部分開;人與人的心臟.


六、實現關係(Implementation)

實現關係(Implementation):是用來規定介面和實線介面的類或者構建結構的關係,介面是操作的集合,而這些操作就用於規定類或者構建的一種服務。

•介面之間也可以有與類之間關係類似的繼承關係和依賴關係,但是介面和類之間還存在一種實現關係(Realization),在這種關係中,類實現了介面,類中的操作實現了介面中所 宣告的操作。在UML中,類與介面之間的實現關係用帶空心三角形的虛線來表示。
public interface Vehicle 
{
    public void move();
}
public class Ship implements Vehicle
{
    public void move() 
    {
    ……
    }
}
public class Car implements Vehicle
{
    public void move() 
    {
    ……
    }
}