帶你掌握 UML 類別圖的 6 種關係

更新於 發佈於 閱讀時間約 8 分鐘

Let's learn 6 relationships of class diagram.

來,你現在是一個軟體設計師,請問你想用什麼方式來體現你的軟體設計呢? 你有什麼更好方式表達來讓你的同事理解你的設計進一步跟你一起協作呢? 我認為在軟體設計的溝通上使用圖形化的工具是相當好的辦法。UML 裡的類別圖(Class Diagram)就是一個很好表達軟體架構設計的工具,要畫好類別圖會需要用到 6 種關係線來定義類別間的關係與如何實作,也是我們這次要關注的主題。

UML 的類別圖是軟體設計視覺化的一種體現

畫線是艱難的任務

在網路上查找可以發現有很多類別圖的 6 種關係的說明與示例,通常不太容易難取得共鳴。主要有兩個原因:

  1. 對於這些關係線的定義混淆,導致無法判斷滿足條件與使用時機
  2. 缺少生活相關的具體案例,很難理解這些關係所對應的抽象概念

類別與介面

這裡需要先插個話,補充一點 OOP 的知識。在 OOP 裡面類別(Class)是成員屬性(Member)與函數方法(Operation)的集合,按照其內容物的差異可分為三種:

  1. 一班類別:有成員屬性跟完全實作的函數方法 ,能直接實體化
  2. 抽象類別:有成員屬性跟不完全實作的函數方法,因為實作不完全不能直接實體化
  3. 抽象介面:只定義函數方法且完全不實作,跟抽象類別一樣不能直接實體化

其他的 OOP 的觀念有機會再說,這裡你需要先記得有類別(Class)跟介面(nterface) 這兩種就好。

類別有三種:一班類別、抽象類別、抽象介面

類別圖的 6 條線

我們繼續回到類別關係上,在類別圖裡定義的 6 種關係線分別是:繼承(Inheritance) ,實現 (Realization),合成 (Composition),聚合 (Aggregation),相依 (Dependency) 以及 關聯 (Association)。

Inheritance, 繼承是全盤接收

繼承關係套用程式書籍的說法叫做「父子」類別,負責繼承的是子類別,被繼承的是父類別,它是描述著兩個類別間具有「上下」關係。繼承概念就是「全盤接收」,子類別會接收父類別的所有屬性成員跟函數方法而且可以直接拿來用,所以子類別繼承後的預設的特性跟行為會跟父類別一致。

繼承關係重點是子類別還可以增加自己需要的成員屬性,利用擴充或複寫父類別的函數方法來跟父類別做出差異。就像我們與父母就是繼承關係,一樣也可以透過日後的學習成長有自己的特色與能力來跟父母產生差異,所謂「青出於藍更勝於藍」就是對繼承關係極佳註解。

Example of Inheritance

Example of Inheritance

在 OOP 的實作上,繼承關係可以是單一繼承或是多重繼承,多重繼承可以一次拿到多個父類別現有的能力,相對的設計跟除錯難度也會變得很高,例如當被繼承的兩個父類別都有一樣的函數方法,請問呼叫這個方法的時候,你覺得會叫到哪一個父類別的函數方法呢?

Realization, 實作是擴增能力

實作也是用來描述兩個類別的上下關係跟繼承類似,只要把的父類別換成是一個或多個抽象介面就可以了,所以實作關係也可以視為一種特殊的繼承關係。抽象介面的設計目的是把一組相關的函數方法(能力)定義出來綑綁在一起,負責實作介面的子類別必須按照介面的要求完全實作所有介面規定的函數方法。

實作的概念就是「有目的性的學習成長」,假設你也想成為程式設計師,那麼你就必須學會當程式設計師所需要的能力,例如至少會一種程式語言、要有編寫程式碼的與除錯的能力、要有代碼管理能力跟持續整合的能力等等。只要有完全實作出這組能力就算你是非本科系出身也可以是位合格的程式設計師了。

Example of Realization

Example of Realization

在 OOP 的實作上,類別可以實作一個到多個介面,在實作關係裡不管實作了多少介面,原則是所有介面有定義的函數方法都要全部實作出來。雖然實作多個介面來獲取能力不像多重繼承一次取得多個父類別的能力這麼方便,不過成功實作所有介面後,這種「能力插件」運作起來可以媲美多重繼承的效果。

Composition, Aggregation 合成/聚合是雙胞胎

合成跟聚合這兩種關係很像所以放在一起講,它們描述的是物件與部件的組合關係。在生活中你應該會觀察到大部分物件都是透過很多個部件組合,透過多個物件合作的方式運作的。

要區分合成或聚合的關鍵就是分析物件與它的部件兩者是否「密不可分」!只要你發現物件跟其部件分離後會出現兩個一起掛點的狀況,就表示兩者關係就是合成;相對的,物件跟部件分開後都活得好好的就叫做聚合。

最經典的合成關係莫過於我們的人體與體內的重要器官,像是心臟大腦… 一旦將它們從我們體內被分離出來,肯定兩個都活不了 ;善用「密不可分」的原則就可以很好的判斷兩個類別之間是合成還是聚合關係。

Example of Composite and Aggregation

Example of Composite and Aggregation

從 OOP 的實作上,合成或聚合的作用範圍都在成員屬性等級,物件類別會建立一個對應「部件」類別型態的成員屬性來保存這個部件。觀察「密不可分」的時候可以往物件解構那段程式去找找,如果你發現物件解構的時候也會把部件也解構掉,就表示兩者「密不可分」是為合成關係,否則就是聚合關係。

如果你是使用 C++ 這類需要手動清除記憶體的程式語言,那麼實作出正確的合成或聚合關係就很重要,因為該解構卻沒被解構的物件會造成記憶體洩漏,導致被佔用的記憶體無法釋放出來,隨時間增加你的程式會開始越來越難配置到記憶體空間,會變慢、變得不穩定,此時離當機也不遠了。

Dependency, 相依是我需要你

相依關係可以解釋為兩個類別間的「需要對方」關係,說到這邊你可能會想,難道合成或聚合裡的物件與部件兩者關係不也是相依關係嗎? 要區分這裡的相依關係的關鍵就是看那些被需要的物件出現的位置,以及這些物件是否有「用完就收」特性。

相依關係的作用範圍僅在函數方法等級,觀察重點在一個被需要的物件是否只出現在需求者物件的函數方法的參數列、程式碼區塊裡面內或是函數方法的回傳值裡面?在來看用完就收,當這些函數方法執行完畢後,這些被需要的物件,不會被保留在需求者物件上。

Example of Dependency

Example of Dependency

相依在概念上跟我們日常生活中臨時需要或是租借關係很像,再回到軟體工程師的例子,白天在公司上班要發揮編程能力時「需要」一台電腦跟外接螢幕作為編成函數方法的輸入(參數)。等下班軟體工程師會歸還這些設備並不會把它們帶回家。

到了 OOP 的實作上,判斷相依關係的撇步只需要去觀察調用它的函數方法裡有沒有把傳進來的物件用一個成員屬性存起來即可,如果沒有就是相依,反之我們就要往前面說的合成或聚合關係去確認了。

Association, 關聯是點頭之交

最後一種是叫做關聯關係,只要求兩個類別有”互相認識”對方就可以了是一種最低限度的關係。所謂認識的方式就是把自己類別的某個屬性開放出去給另一個需要認識自己的類別裡面。

Example of Association

Example of Association

這種關聯概念很像我們去訂閱某個資訊或服務,就像前陣子我想在網路書店購買一本原文書結果缺貨,於是我用電子郵件跟網路書店產生關聯,我把電子郵件放給網路書店,請它在有庫存的時候通知我;關聯關係也可是雙向多重的,反過來我也可以自己去訂閱各家書店的書本庫存數寄到我的電子郵件裡,只要發現有庫存我就可以去訂書。

關聯關係是一種平等自由、雙向多重的關係。它讓類別之間可以即時了解對方的狀況,再由類別實體們自己決定是否要根據這個狀態的改變來行動。

在 OOP 的實作上,會把這種關聯性建立在類別變數上,類別變數的概念可以理解為屬於該類別的全域變數,只要這個全域變數有變,則所有繼承這個類別實體物件自然也都會「自動」收到通知,當物件收到到訊息的後會決定如何做出反應。

總結:

以上就是這次要跟你聊的在 UML 裡的類別圖裡會用到的 6 種類別間的關係,如果你是第一次聽到感覺好像很複雜不容易弄懂,這是學習過程中很正常的現象,不需要浪費時間在自我懷疑身上,只要你願意多接觸,多花點時間,稍微靜下心弄清楚了定義(判斷標準),遇到抽象的觀念就嘗試用自己身邊熟悉的事物來類比,轉換成自己的語言,相信你也很快就能掌握 6 條線,讓這些設計語言成為你軟體設計工作與團隊溝通的利器。

留言
avatar-img
留言分享你的想法!
avatar-img
Warren Lo的沙龍
22會員
70內容數
WarrenLo's 軟體設計武功祕笈
Warren Lo的沙龍的其他內容
2024/09/25
當我們從事軟體開發工作一段時間後,有些人會開始接觸軟體架構設計。由於每個軟體架構設計者的對問題的理解與知識經驗差異會導出不同的設計架構。近期與同事的軟體設計案例經驗交流後,就很希望自己剛開始學習軟體架構設計的時候就有人能用實際的軟體架構設計經驗來帶我入門...
Thumbnail
2024/09/25
當我們從事軟體開發工作一段時間後,有些人會開始接觸軟體架構設計。由於每個軟體架構設計者的對問題的理解與知識經驗差異會導出不同的設計架構。近期與同事的軟體設計案例經驗交流後,就很希望自己剛開始學習軟體架構設計的時候就有人能用實際的軟體架構設計經驗來帶我入門...
Thumbnail
2024/07/02
如果你也是從事軟體相關工作的人,一定會遭遇突然需要你去學習一套你不熟悉的程式語言狀況吧,此時你會怎麼做呢? 是趕快去買書來看嗎? 還是趕快找一門程式課來上? 又或者乾脆去找會的同事來教學?
Thumbnail
2024/07/02
如果你也是從事軟體相關工作的人,一定會遭遇突然需要你去學習一套你不熟悉的程式語言狀況吧,此時你會怎麼做呢? 是趕快去買書來看嗎? 還是趕快找一門程式課來上? 又或者乾脆去找會的同事來教學?
Thumbnail
2024/04/08
經過這麼多年的觀察與實踐,一個成熟的軟體工程師還需要第四個要素,它是讓決定你通往熟手的重要關鍵沒有之一。
Thumbnail
2024/04/08
經過這麼多年的觀察與實踐,一個成熟的軟體工程師還需要第四個要素,它是讓決定你通往熟手的重要關鍵沒有之一。
Thumbnail
看更多
你可能也想看
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這個章節主要介紹了Swift程式語言中物件導向程式設計的基本概念,包括類別、建構子、公開、私有、受保護等等的概念。同時,也介紹了繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射等進階特性。
Thumbnail
這個章節主要介紹了Swift程式語言中物件導向程式設計的基本概念,包括類別、建構子、公開、私有、受保護等等的概念。同時,也介紹了繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射等進階特性。
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
Thumbnail
本章節旨在介紹JavaScript中的物件導向編程。內容包括類別(Class)的定義和使用,建構子的作用,以及公開,私有,受保護(Protected)等不同訪問修飾符的概念。此外,還涵蓋了繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型、反射等物件導向的主要觀念。
Thumbnail
本章節旨在介紹JavaScript中的物件導向編程。內容包括類別(Class)的定義和使用,建構子的作用,以及公開,私有,受保護(Protected)等不同訪問修飾符的概念。此外,還涵蓋了繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型、反射等物件導向的主要觀念。
Thumbnail
本章節的目的是讓讀者瞭解C#的物件導向特性,包括類別、繼承、多型、封裝等基本概念,以及介面、抽象類別、靜態類別等進階主題。此外,本章節也將介紹如何使用列舉、委派、Lambda表達式、泛型及反射,這些都是C#中常見的強大功能。
Thumbnail
本章節的目的是讓讀者瞭解C#的物件導向特性,包括類別、繼承、多型、封裝等基本概念,以及介面、抽象類別、靜態類別等進階主題。此外,本章節也將介紹如何使用列舉、委派、Lambda表達式、泛型及反射,這些都是C#中常見的強大功能。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
在網路上查找可以發現有很多類別圖的 6 種關係的說明與示例,通常不太容易難取得共鳴。主要有兩個原因: 1. 對於這些關係線的定義混淆,導致無法判斷滿足條件與使用時機 2. 缺少生活相關的具體案例,很難理解這些關係所對應的抽象概念
Thumbnail
在網路上查找可以發現有很多類別圖的 6 種關係的說明與示例,通常不太容易難取得共鳴。主要有兩個原因: 1. 對於這些關係線的定義混淆,導致無法判斷滿足條件與使用時機 2. 缺少生活相關的具體案例,很難理解這些關係所對應的抽象概念
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News