類圖用于描述系統中所包含的類以及它們之間的相互關系,幫助人們簡化對系統的理解,它是系統分析和設計階段的重要產物,也是系統編碼和測試的重要模型依據。接下來我們就來談談類圖的組成,在下一篇中我們將討論一下類圖之間的關系。
### 一、類圖的組成
1. 普通類

上圖就是一個UML的普通類圖,從上圖我們看出,一個UML通常由三部分組成。
**第一部分是類名:**每個類都必須有一個名字,類名是一個字符串。
**第二部分是類的屬性(Attributes):**屬性是指類的性質,即類的成員變量。一個類可以有任意多個屬性,也可以沒有屬性。
屬性的格式:
~~~
可見性 名稱:類型 [ = 缺省值 ]
~~~
其中:
**可見性**表示該屬性對于類外的元素而言是否可見,包括公有(public)、私有(private)和受保護(protected)三種,在類圖中分別用符號+、-和#表示。
**名稱**表示屬性名,用一個字符串表示。
**類型**表示屬性的數據類型,可以是基本數據類型,也可以是用戶自定義類型。
**缺省值**是一個可選項,即屬性的初始值。
**第三部分是類的操作(Operations):**操作是類的任意一個實例對象都可以使用的行為,是類的成員方法。
操作的格式:
~~~
可見性 名稱(參數列表) [ : 返回類型]
~~~
其中:
**可見性**的定義與屬性的可見性定義相同。
**名稱**即方法名,用一個字符串表示。
**參數列表**表示方法的參數,其語法與屬性的定義相似,參數個數是任意的,多個參數之間用逗號“,”隔開。
**返回類型**是一個可選項,表示方法的返回值類型,依賴于具體的編程語言,可以是基本數據類型,也可以是用戶自定義類型,還可以是空類型(void),如果是構造方法,則無返回類型。
**下劃線**表示這個方法是靜態方法。
2. 抽象類

就像上圖展示的,抽象類和普通類的區別就是抽象類的名稱是用斜體寫的,并且抽象類中的抽象方法也是斜體的。
3. 接口


接口有上邊兩種方法,第一種方法是在類的前邊加上<>,這樣這個類就變成了接口類;第二種方法是先聲明一個接口,圓圈旁邊就是接口的名稱,然后與實現它的類聯系起來,對第二種方法的表示我個人還是不太能理解,圓圈里并沒有寫這個接口有什么方法啊,實現它的類中到時有接口的方法,但是又怎么能區分的出哪些是接口的哪些是本身的呢?還請知道的大神講解一下。
### 二、類圖中的關系
1. 關聯關系
關聯(Association)關系是類與類之間最常用的一種關系,它是一種結構化關系,用于表示一類對象與另一類對象之間有聯系,如汽車和輪胎、師傅和徒弟、班級和學生等等。在UML類圖中,用實線連接有關聯關系的對象所對應的類,在使用Java、C#和C++等編程語言實現關聯關系時,**通常將一個類的對象作為另一個類的成員變量**。在使用類圖表示關聯關系時可以在關聯線上標注角色名,一般使用一個表示兩者之間關系的動詞或者名詞表示角色名(有時該名詞為實例對象名),關系的兩端代表兩種不同的角色,因此在一個關聯關系中可以包含兩個角色名,角色名不是必須的,可以根據需要增加,其目的是使類之間的關系更加明確。
在UML中,關聯關系通常又包含如下幾種形式:
**(1) 雙向關聯**
默認情況下,關聯是雙向的。例如:顧客(Customer)購買商品(Product)并擁有商品,反之,賣出的商品總有某個顧客與之相關聯。因此,Customer類和Product類之間具有雙向關聯關系,如圖所示:

**(2) 單向關聯**
類的關聯關系也可以是單向的,單向關聯用帶箭頭的實線表示。例如:顧客(Customer)擁有地址(Address),則Customer類與Address類具有單向關聯關系,如圖所示:

**(3) 自關聯**
在系統中可能會存在一些類的屬性對象類型為該類本身,這種特殊的關聯關系稱為自關聯。例如:一個節點類(Node)的成員又是節點Node類型的對象,如圖所示:

**(4) 多重性關聯**
多重性關聯關系又稱為重數性(Multiplicity)關聯關系,表示兩個關聯對象在數量上的對應關系。在UML中,對象之間的多重性可以直接在關聯直線上用一個數字或一個數字范圍表示。
對象之間可以存在多種多重性關聯關系,常見的多重性表示方式如表所示:
| 表示方式 | 多重性說明 |
|-----|-----|
| 1..1 | 表示另一個類的一個對象只與該類的一個對象有關系 |
| 0..* | 表示另一個類的一個對象與該類的零個或多個對象有關系 |
| 1..* | 表示另一個類的一個對象與該類的一個或多個對象有關系 |
| 0..1 | 表示另一個類的一個對象沒有或只與該類的一個對象有關系 |
| m..n | 表示另一個類的一個對象與該類最少m,最多n個對象有關系 (m≤n) |
例如:一個界面(Form)可以擁有零個或多個按鈕(Button),但是一個按鈕只能屬于一個界面,因此,一個Form類的對象可以與零個或多個Button類的對象相關聯,但一個Button類的對象只能與一個Form類的對象關聯,如圖所示

2. 聚合關系
**聚合是關聯關系的一種特例,他體現的是整體與部分、擁有的關系,即has-a的關系**,此時整體與部分之間是可分離的,他們可以具有各自的生命周期,部分可以屬于多個整體對象,也可以為多個整體對象共享在UML中,聚合關系用帶空心菱形的直線表示。例如:汽車發動機(Engine)是汽車(Car)的組成部分,但是汽車發動機可以獨立存在,因此,汽車和發動機是聚合關系,如圖所示:

在代碼實現聚合關系時,成員對象通常作為構造方法、Setter方法或業務方法的參數注入到整體對象中。
3.組合關系
**組合也是關聯關系的一種特例,他體現的是一種contains-a的關系**,這種關系比聚合更強,也稱為強聚合;他同樣體現整體與部分間的關系,但此時整體與部分是不可分的,整體的生命周期結束也就意味著部分的生命周期結束。在UML中,組合關系用帶實心菱形的直線表示。例如:人的頭(Head)與嘴巴(Mouth),嘴巴是頭的組成部分之一,而且如果頭沒了,嘴巴也就沒了,因此頭和嘴巴是組合關系,如圖所示

4.依賴關系
可以簡單的理解,就是**一個類A使用到了另一個類B**,而這種使用關系是具有偶然性的、臨時性的、非常弱的,但是B類的變化會影響到A;比如某人要過河,需要借用一條船,此時人與船之間的關系就是依賴;表現在代碼層面,為類B作為參數被類A在某個method方法中使用;
在UML中,依賴關系用帶箭頭的虛線表示,由依賴的一方指向被依賴的一方。例如:駕駛員開車,在Driver類的drive()方法中將Car類型的對象car作為一個參數傳遞,以便在drive()方法中能夠調用car的move()方法,且駕駛員的drive()方法依賴車的move()方法,因此類Driver依賴類Car,如圖所示:

5.泛化關系
**泛化(Generalization)關系也就是繼承關系,用于描述父類與子類之間的關系**,父類又稱作基類或超類,子類又稱作派生類。在UML中,泛化關系用帶空心三角形的直線來表示。在代碼實現時,我們使用面向對象的繼承機制來實現泛化關系,如在Java語言中使用extends關鍵字、在C++/C#中使用冒號“:”來實現。例如:Student類和Teacher類都是Person類的子類,Student類和Teacher類繼承了Person類的屬性和方法,Person類的屬性包含姓名(name)和年齡(age),每一個Student和Teacher也都具有這兩個屬性,另外Student類增加了屬性學號(studentNo),Teacher類增加了屬性教師編號(teacherNo),Person類的方法包括行走move()和說話say(),Student類和Teacher類繼承了這兩個方法,而且Student類還新增方法study(),Teacher類還新增方法teach()。如圖所示:

6.實現關系
接口之間也可以有與類之間關系類似的繼承關系和依賴關系,但是接口和類之間還存在一種實現(Realization)關系,在這種關系中,**類實現了接口,類中的操作實現了接口中所聲明的操作**。在UML中,類與接口之間的實現關系用帶空心三角形的虛線來表示。例如:定義了一個交通工具接口Vehicle,包含一個抽象操作move(),在類Ship和類Car中都實現了該move()操作,不過具體的實現細節將會不一樣,如圖所示:

### 三、關系之間的區別
1.聚合與組合
(1)聚合與組合都是一種結合關系,只是額外具有整體-部分的意涵。
(2)部件的生命周期不同
聚合關系中,整件不會擁有部件的生命周期,所以整件刪除時,部件不會被刪除。再者,多個整件可以共享同一個部件。
組合關系中,整件擁有部件的生命周期,所以整件刪除時,部件一定會跟著刪除。而且,多個整件不可以同時間共享同一個部件。
(3)聚合關系是“has-a”關系,組合關系是“contains-a”關系。
2.關聯和聚合
(1)表現在代碼層面,和關聯關系是一致的,只能從語義級別來區分。
(2)關聯和聚合的區別主要在語義上,關聯的兩個對象之間一般是平等的,例如你是我的朋友,聚合則一般不是平等的。
(3)關聯是一種結構化的關系,指一種對象和另一種對象有聯系。
(4)關聯和聚合是視問題域而定的,例如在關心汽車的領域里,輪胎是一定要組合在汽車類中的,因為它離開了汽車就沒有意義了。但是在賣輪胎的店鋪業務里,就算輪胎離開了汽車,它也是有意義的,這就可以用聚合了。
3.關聯和依賴
(1)關聯關系中,體現的是兩個類、或者類與接口之間語義級別的一種強依賴關系,比如我和我的朋友;這種關系比依賴更強、不存在依賴關系的偶然性、關系也不是臨時性的,一般是長期性的,而且雙方的關系一般是平等的。
(2)依賴關系中,可以簡單的理解,就是一個類A使用到了另一個類B,而這種使用關系是具有偶然性的、臨時性的、非常弱的,但是B類的變化會影響到A。
4.綜合比較
這幾種關系都是語義級別的,所以從代碼層面并不能完全區分各種關系;但總的來說,后幾種關系所表現的強弱程度依次為:
**組合>聚合>關聯>依賴;**
- 前言
- 設計原則(一)&quot;開-閉&quot;原則(OCP)
- 設計原則(二)里氏替換原則(LSP)
- 設計原則(三)組合復用原則
- 設計原則(四)依賴倒置原則(DIP)
- 設計模式(一)簡單工廠模式
- 設計模式(二)工廠方法模式
- 設計模式(三)抽象工廠模式
- 設計模式(四)單例模式
- 設計模式(五)創建者模式(Builder)
- 設計模式(六)原型模式
- 設計模式(七)門面模式(Facade Pattern 外觀模式)
- 設計模式(八)橋梁模式(Bridge)
- 設計模式(九)裝飾模式(Decorator)
- 設計模式(十)適配器模式
- 設計模式(十一)策略模式
- 設計模式(十二)責任鏈模式
- 設計模式之UML(一)類圖以及類間關系(泛化 、實現、依賴、關聯、聚合、組合)
- 設計模式之橋梁模式和策略模式的區別