類別圖中的類別節點可以把每一個類別所有的內容呈現出來,也可以只有顯示類別之間的關聯,這些關聯就是程式碼之間的相依性。這一點非常重要,因為要從一大堆原始程式碼中找出它們之間的相依性,相對之下是比較困難的。使用類別圖型可以讓你清楚的瞭解某一些特定的相依性,尤其在一個高度抽象化的軟體系統中,瞭解這個特性更加重要。
類別圖型最重要的特性之一,就是可以表現出軟體系統裡,所有關鍵類別的關聯。使用類別圖型來呈現這些關聯的資訊,不論是應用在系統的分析與程式設計師之間的討論,都比直接使用原始程式碼來得容易許多。
繼承(extends)
經過抽象化的動作後,往往會產生許多類別之間的繼承關係,使用類別圖型的繼承表示方法可以清楚的瞭解複雜的繼承架構,類別圖型使用「Generalization arrow」來表示類別之間繼承的關聯:
從上列的類別圖型,可以很清楚的知道這些類別之間的繼承關係:
在類別圖型中如果詳細的表現出類別節點的資訊,包含所有的屬性和方法定義,你可以從圖中知道子類別繼承了哪些成員,如果子類別繼承的是一個抽象類別,也可以知道子類別必需實作哪些方法,這在龐大的繼承架構裡非常有用:
實作(implements)
類別圖型使用「Realization arrow」來表示類別之間的實作關聯:
上列的類別圖型也可以使用簡化的介面表示方法:
結合
類別和類別之間的關聯都可以稱為「結合、Association」。使用結合
可以表現類別之間的:
- 抽象的結合關聯。例如「擁有」或「使用」
- 抽象的結合角色。例如「線上客戶」或「系統管理員」
- 結合的數量。例如「Car」與「Wheel」的結合數量是1跟4
- 結合的方向。例如表示「使用者」與「被使用者」
將這些結合的元素使用在圖型的話,會像這樣:
以上列的圖型來說,可以在結合線條上直接使用箭頭來表示方向,這樣就可以省略掉結合方向的符號,這也是一般比較常用的作法:
上列的結合範例圖型,對應到Java類別的宣告會像這樣:
在結合關係裡,結合數量通常表示軟體系統中一些重要的行為,關於結合數量的標示可以使用下列幾種方法:
- 數字:確定的數量
- *:零到多個
- 0..*:零到多個
- 0..1:零到一個
- 1..*:一到多個
- n..m:最少n個,最多m個
Java在結合數量上的實作,可以使用下列幾種方法:
- 允許零個時,表示物件變數的值可以是「null」
- 確定的數量可以使用陣列或集合資料結構
- 不確定的數量可以使用集合資料結構
下列是一個使用不同結合數量的類別圖型範例:
上列的結合範例圖型,對應到Java類別的宣告會像這樣:
在軟體系統的實作上,類別之間產生相依性的狀況無所不在,上列討論的幾種結合狀況,是比較明顯的。但是相依性的意思應該是說「在軟體系統中的A類別會使用到B類別」,從這個條件來看,如果缺少了B類別,那這個軟體系統當然會出問題。
所以在結合關係裡,也可以使用「Stereotypes」來表示一些特殊的結合特性,讓類別圖型的結合特性可以更接近軟體系統的實作:
- \<\>
在「Foo」類別的區塊中建立與使用「Qoo」物件,只是一種區域變數,生命週期只有在區塊裡,彼此之間沒有直接的關係。 - \<\>
在「Foo」類別中透過參數來取得「Qoo」物件,建立「Qoo」物件的責任在呼叫方法的類別。這種結合情況有另外一種常見的表示方法:
- \<\>
「Qoo」物件由「Foo」負責建立,然後傳給需要的地方,這種作法稱為「Factory method」,是一種常見的「設計模式、Design pattern」。 - \<\>
「Delegate」是代理的意思,「Foo」類別在這種情況下扮演「代理者」的角色,由「Foo」類別負責將方法的呼叫轉為呼叫「Qoo」的方法,有許多設計模式都會使用這種結合,例如Command、Proxy或Composite。
聚合
「聚合、Aggregation」是一種特殊情況的結合關係,它建立在「整體、whole」與「成員、member」的概念上,這個整體必須擁有這些成員才具有意義:
以上列的範例來說,如果一台沒有有引擎、車門和輪子的車子,應該就不算是一台車子;但是引擎、車門和輪子都是可以獨立存在,並且有它們各自的用途,例如引擎不一定要裝在車子上。
聚合在Java的實作上,並沒有特別明顯的方法,它跟一般的結合並沒有什麼差別,對Java程式設計師來說,唯一該注意的地方,就是要確定被擁有者一定會被建立:
組合
「組合、Composition」是一種特殊情況的聚合關係,它跟聚合的差別在於方向的角度,你可以把聚合視為「單向」,而把組合看成「雙向」的結合關係:
在上列的範例中,一個課程必須擁有學生與教材,才算是一個課程,這個特性跟聚合是一樣的;但是學生與教材也必須有課程開課了,才能夠去上課,也就是說如果沒有課程存在,學生與教材是沒有意義的。
組合在Java的實作上,跟聚合一樣,同樣要確定被擁有者一定會被建立:
因為組合的特性,另外要注意兩個在實作上的狀況:
- 一個成員物件不能同時被兩個擁有者擁有
- 擁有者要負責成員的的生命週期
在Java技術中,物件的「解構、deconstruct」是透過「Garbage collection」來完成的,程式設計師並不需要去管理物件的生命週期;但是在一些特殊的情況下,你可能需要覆寫「Object」類別中的「finalize」方法,在這個方法中處理解構物件該作的事情,例如中斷取得的網路連線。
巢狀類別
「巢狀類別、Nested class」的應用非常多,你可以使用下列的結合關係來表示內部類別:
上列的圖型範例對應到類別的宣告會像這樣:
巢狀類別中有一種比較特殊的情形是「匿名類別、Anonymous class」,UML並沒有特別制定關於匿名類別的表示方法,所以同樣使用巢狀類別的表示方法,但是在類別節點上作一些調整:
上列的圖型在傳統的「AWT」圖形介面中很常見,對應到類別的宣告會像這樣:
結合類別
在討論聚合時使用的範例圖型,它所顯示出來的資訊還是不夠詳細:
如果想要圖型中顯示容器的種類,可以使用「結合類別、Association class」來表示:
這樣的顯示方法,在比較複雜的類別結合情況下,可以很清楚的看出彼此的結合關係。以下列的範例圖型來說,這種類別圖型並沒有辦法表達出所有的資訊:
改用結合類別來表示的話,可以補足上圖欠缺的資訊:
上列的圖型範例對應到「Course」和「Registration」的類別宣告會像這樣:
限定結合
「限定結合、Qualifier associations」是一種特殊的結合表示方法,可以在結合關係中顯示索引的資訊。最常見的情況是在使用「Map」資料結構的時候:
上列的圖型範例,對應到「StudentProperty」類別的宣告會像這樣: