- UML 建模、設計與分析:從新手到高手
- 夏麗華
- 6501字
- 2019-12-09 14:44:27
4.4 關聯關系
對象之間也需要定義通信手段,UML規范中對象之間的通信手段就稱為關系。類圖中的關聯定義了對象之間的關系準則,在應用程序創建和使用關系時,關聯提供了維護關系完整性的規則。類關系的強弱基于該關系所涉及的各類間彼此的依賴程度。彼此相互依賴性較強的兩個類稱為緊密耦合。在這種情況下,一個類的改變極可能影響到另一個類。緊密耦合通常是一個壞事。
4.4.1 二元關聯
關聯意味著類實際上以屬性的形式包含對其他類的一個或多個對象的引用。確定了參與關聯的類之后,就可以對關聯進行建模了。只有兩個類參與的關聯可以稱為二元關聯;多于兩個類參與的關聯,即為n元關聯。在類圖中二元關聯定義了兩個類的對象之間的關系準則,關聯定義了什么是允許的,什么是不允許的。如果兩個類在類圖中具有關聯關系,那么在對象圖中這兩個類的相應對象所具有的關系被稱為鏈。關聯描述的是規則,而鏈描述的是事實。如下圖所示演示了Person類和Car類之間的關聯關系。Person類定義了人對象及其功能,Car類則定義了小汽車對象及其功能。兩者間的關聯是一種單一類型的關系,存在于兩者的對象之間,解釋了這些對象需要通信的原因。

一個完整的關聯包括類之間關聯關系的直線和兩個關聯端點。如下圖所示演示了關聯的組成。其中直線以及關聯名稱定義了該關系的標志和目的,關聯端點定義了參與關聯的對象所應遵循的規則。在UML規范中關聯端點是一個元類,它擁有自己的屬性,例如多重性、約束、角色等。

1.關聯的名稱
關聯的名稱表達了關聯的內容,含義確切的名稱使人更容易理解。如果名稱含糊不清,就容易引起誤解和爭論,導致建模開銷的增加和建模效率的降低。一般情況下,使用一個動詞或者動詞短語命名關聯關系。下圖顯示的是同一關聯的兩個不同的名稱,即“holds”和“is holded by”。

在命名關聯關系時存在如下假定:如果要從相反的方向理解該關聯,只需將關聯名稱的意義反過來理解。例如,上圖中的關聯可以理解為“Person對象擁有Car對象”,如果從相反的方向理解也是可以的,即“Car對象被Person對象擁有”。因而,對于上圖中的關聯,只建立其中一個模型即可。
通常情況下,人們喜歡從左到右地閱讀,所以當希望讀者從右向左閱讀時,應使用某種方法告訴讀者,這時就可以使用方向指示符。可以將方向指示符放在關聯名稱的某一側,以向讀者說明應如何理解關聯名稱。上圖中兩個關聯名稱都使用方向指示符,該指示符是兩個黑三角。事實上,第一個不必使用,因為該名稱的閱讀順序符合人們的閱讀習慣;只有在閱讀順序不符合人們的閱讀習慣時,才有必要使用方向指示符。
對關聯進行命名是為了清晰而簡潔地說明對象間的關系,同時可以用于指導對象之間的通信方式定義,也決定每個對象在通信中所扮演的角色。
2.關聯的端點
為了定義對象在關聯中所扮演的角色,UML將關聯中的每個端點都作為具有相應規則的獨立實體。因而,在“holds”關聯中Person對象的參與跟Car對象的參與是不同的。
每個關聯端點都包含了如下內容:端點上的對象在關聯中扮演什么角色,有多少對象可以參與關聯,對象之間是否按一定的順序進行排列,是否可以用對象的一些特征對該對象進行訪問,以及一個端點的對象是否可以訪問另一個端點的對象等。
關聯端點可以包含諸如角色、多重性、定序、約束、限定符、導航性、可變性等特征中的部分或者全部。
3.關聯中的角色
角色是關聯關系中一個類對另一個類所表現出來的職責,任何關聯關系中都涉及與此關聯有關的角色,也就是與此關聯相連的類的對象所扮演的角色。在下圖中,人在“enjoy”這一關聯關系中扮演的是觀眾這一角色;演出是演員表演的結果,因而Performance對象所扮演的角色就是演員。

與關聯名稱相比,角色名稱從另外一個角度描述了不同類型的對象是如何參與關聯的。關聯中的角色通常用字符串命名,角色可以是名詞或名詞短語,以解釋對象是如何參與關聯的。類圖中角色名通常放在與此角色有關的關聯關系(代表關聯關系的直線)的末端,并且緊挨著使用該角色的類。角色名不是類的組成部分,一個類可以在不同的關聯中扮演不同的角色。
由于角色名稱和關聯名稱都被用來描述關系的目的,所以角色名稱可以代替關聯名稱,或者兩者同時使用。例如,上圖中前面的模型同時使用了關聯名稱和角色名稱,后面的模型只使用了角色名稱,這兩種表示關聯的方法都是可行的。
與關聯的名稱不同,位于關聯端點的角色名可以生成代碼。每個對象都需要保存一個參考值,該參考值指向一個或者多個關聯的對象。在對象中,參考值是一個屬性值,如果只有一個關聯,就只有一個屬性來保存參考值。在生成的代碼中,屬性使用參考對象的角色名命名。
4.可見性
相關人員可以使用可見性符號修飾角色名稱,以說明該角色名稱可以被誰訪問,如下圖所示。

上圖中,Performance類的參考值指向角色名稱“-Audience”,該角色名稱前面的“-”表示可見性類型為Private,這說明類Performance包含一個私有屬性,它保存了一個參考值指向Person對象。
提示
由于上圖中屬性的可見性為Private,所以要想訪問該屬性則需要使用一個可見性不是Private的操作。另外,UML 2.0版本中關聯端點已不再使用可見性的概念。
5.多重性
關聯的多重性指的是有多少對象可以參與關聯,它可用來表達一個取值范圍、特定值、無限定的范圍或者一組離散值。在UML中,多重性是用由數字標識的范圍來表示的,其格式為“mininum..maxinum”,其中mininum和maxinum都表示int類型。例如0..9,它所表示的范圍的下限為0,上限為9,下限和上限用兩個圓點進行分隔,該范圍表示所描述實體可能發生的次數是0到9中的某一個值。
多重性也可以使用符號“*”來表示一個沒有上限或者說上限為無窮大的范圍。例如,范圍0..*表示所有的非負整數。下限和上限都相同的范圍可以簡寫為一個數字。例如,范圍2..2可以用數字2來代替。
除上面介紹的表示外,多重性還可以用另外一種形式來表示,即用一個由范圍和單個數字組成的列表來表示,列表中的元素通常以升序形式排列。例如,有一個實體是可選的,但如果發生的話,就必須至少發生兩次以上,那么在建模時就可以用多重性0,3..*來表示。
賦給一個關聯端點的多重性表示在該端點可以有多個對象與另一個端點的一個對象關聯。例如,下圖中所示的關聯具有多重性,它表示一個人可以擁有0輛或者多輛小汽車。

6.定序
在關聯中使用多重性時可能會有多個對象參與關聯。當有多個對象時還可以使用定序約束,定序就是指將一組對象按一定的順序排列。UML規范中的布爾標記值ordered用于說明是否要對對象進行排序。要指出參與關聯的一組對象需要按一定的順序排列,只需將關鍵字{ordered}置于關聯端點處就可以了。例如,下圖中一個Person對象可以擁有多個Car對象,這些Car對象被要求按照一定的順序進行排列。如果對象不需要按照一定的順序進行排列,那就可以省略關鍵字{ordered}。

前面已經介紹過在系統實現時關聯被定義為保存了參考值的屬性,該參考值指向一組參與關聯的對象。在為對象規定了定序約束后,對象必須按照一定的順序排列,因此實現關聯時必須考慮關聯的標準,以及如何在保持正確順序的前提下向隊列中添加對象或者從隊列中刪除對象。
7.約束
UML定義了3種擴展機制:標記值、原型和約束。約束定義了附加于模型元素之上的限制條件,保證了模型元素在系統生命周期中的完整性。約束的格式實際上是一個文本字符串(使用特定的語言表達),幾乎可以被附加到模型中的任何元素上。約束使用的語言可以是OCL、某種編程語言,甚至也可以是自然語言,如英文、中文等。
在關聯端點上,約束可以被附加到{ordered}特性字符串里。例如,下圖中,ordered后面添加了一個約束,該約束限定與Person對象關聯的一個Car對象的價格不能超過$100000。

約束規定了實現關聯端點時必須遵守的一些規則。如前所述,關聯是使用包含參考對象的屬性來表現的,在系統實現時需要編寫一些方法,以創建或者改變參考值,關聯端點的約束就是在這些方法中實現的。
關聯端點上的約束還可以用于限定哪些對象可以參與關聯。例如,某國為了保護本國的汽車制造業,規定本國公民只能購買國產的小汽車,而不能購買市場上的非國產小汽車,這時可以在模型中使用約束,用布爾值homemade來表示,如下圖所示。

提示
約束條件的作用對象是靠近它的關聯端點的類,在模型中使用約束時要使約束條件靠近它所作用的類。在不熟悉OCL之前,可以使用自然語言表示約束。
8.限定符
限定符定義了被參考對象的一個屬性,并且可以將該屬性作為直接訪問被參考對象的關鍵字。當需要使用某些信息作為關鍵字來識別對象集合中的一個對象時,可以使用限定符。使用限定符的關聯被稱為受限關聯。
限定符提供了一種切實可行的實現直接訪問對象的方法。要建立限定符的模型,首先必須確定希望直接訪問的對象的類型,以及提供被訪問對象的類型,限定符被放在希望實現直接訪問的對象附近。
在現實系統中,限定符和用作對象標識的屬性之間通常是密切聯系的。例如,下圖中,Class具有每個學生的信息,每個學生都有唯一的標識。但是,該類圖中并沒有清楚地指出每個學生的編號是否是唯一的。

為了能夠在類圖中描述這一約束,建模者通常將用作標識的屬性stuID作為類Class的一個限定符,如下圖所示。對于識別對象身份這類問題來說,沒有必要在數據模型中引入一個充當標識的屬性,而應該用限定符來描述對象的標識。

9.導航性
導航性用來描述一個對象通過鏈進行導航訪問另一個對象。也就是說,對一個關聯端點設置導航屬性意味著本端的對象可以被另一端的對象訪問。導航性使用置于關聯端點的箭頭表示。如果存在箭頭,就表示該關聯端點是可導航的,反之則不成立。例如,下圖中,“holds”關聯靠近Car類端點的導航性被設置為真。UML使用一個指向Car的箭頭表示,這意味著另一端的Person對象可以訪問Car對象。

所以,如果兩個關聯端點都是可導航的,就應該在關聯的兩個端點處都放置箭頭。但在這種情況下,大多數建模工具采用了默認的0表示方法,即兩個箭頭都不顯示。原因是:大多數關聯都是雙向的。因而,除非特別聲明,一般都把代表導航性的箭頭省略了。但是,如果采用默認表示方法,在生成代碼時指向關聯對象的參考值將被作為對象屬性實現,并且會有一些操作負責處理該屬性。操作和屬性最終被寫成代碼,其中自然也包括了作為關聯端點一部分的導航性,這樣勢必會增加代碼量,并且增加編碼和維護方面的開銷。
提示
千萬不要把導航箭頭和方向指示符混淆了,前者一般被置于關聯直線的尾部,而方向指示符則置于關聯名稱的左側或右側。
10.可變性
可變性允許建模者對屬于某個關聯的鏈進行操作,默認情況是允許任何形式的編輯。例如,添加、刪除等。在UML中,可變性的默認值可以不在模型中表現出來。但是,如果需要對可變性做些限定,則需要將可變性的取值放在特性字符串中,和定序以及約束放在一起。在預定義的可變性選項中,{frozen}表示鏈一旦被建立,就不能移動或者改變。如果應用程序只允許創建新鏈而不允許刪除鏈,則可以使用{addOnly}選項。
如下圖所示為Contract類和Company類之間的關聯模型。它表示某大學和某建筑公司簽訂合同,由建筑公司負責建造該大學的圖書館,合同是兩者之間的法定關系,為了避免意想不到的錯誤刪除,在該關聯的Contract端點上設置了{frozen}特性。

4.4.2 關聯類
有時關聯本身會引進新類,當想要顯示一個類涉及兩個類的復雜情況時,關聯類就顯得特別重要。關聯類就是與一個關聯關系相連的類,它并不位于表示關聯關系的直線兩端,而是對應一個實際的關聯,用關聯類表示該關聯的附加信息。關聯中的每個連接與關聯類中的一個對象相對應。
雖然類的屬性描述了實例所具有的特性,但有時卻需要將對象的有關信息和對象之間的鏈接放在一起,而不是放在不同的類中。如下圖所示演示了Student和Course之間的Elect關聯。

關聯類是一種將數據值和鏈接關聯在一起的手段,使用關聯類可以增加模型的靈活性,并能夠增強系統的易維護性,因此應該在模型中盡量使用關聯類。UML中,關聯類是一種模型元素,它同時具有關聯和類的特性。
關聯類和其他類非常相似,兩者之間的區別就在于對它們的使用需求不同。一般的類描述的都是某個實體,即看得見摸得著的東西。而關聯類描述的則是關系,它可以像關聯那樣將兩個類連接在一起,也可以像類一樣具有屬性,其屬性用來存儲相應關聯的信息。
如果用戶需要記錄學生所選課程的成績,再使用上圖就不能符合其要求了。重新以學生、課程和成績為例,課程的得分并不是學生本來就有的,只有在學生選修了某門課程后,才會有所選課程的得分。也就是說,課程的得分可以將學生和課程關聯起來。如下圖所示的關聯類用來存儲學生選修的某一門課程的成績,該關聯類代替了上圖中的關聯關系。關聯類的名稱可以寫在關聯的旁邊,也可以放在類標志的名稱分欄當中,關聯類的標志要用一條虛線與它所代表的關聯連接起來。

假設要求每個學生必須明確登記所選的課程,那么每個登記項中就應包含所選課程的得分及其授課學期。可以認為班級是由若干名選修同一課程的學生組成的,將班級定義為登記項的集合,即班級是由特定學期選修相同課程的學生組成的。如下圖所示,通過一個用來識別對應于特定類的登記項的關聯可以描述這種情況。

4.4.3 或關聯與反身關聯
前面已經介紹過一個類可以參與多個關聯關系,如下圖所示是保險業務的類圖。個人可以同保險公司簽訂保險合同,其他公司也可以同保險公司簽訂保險合同。但是,個人持有的合同不同于一般公司持有的合同。也就是說,個人與保險合同的關聯關系不能跟公司與保險合同的關聯關系同時發生。當這兩個關聯不能同時并存時,應該怎樣表示呢?

答案很簡單,UML提供了一種或關聯來建模這樣的關聯關系。或關聯是指對多個關聯附加約束條件,使類中的對象一次只能參與一個關聯關系。或關聯的表示方法如下圖所示,當兩個關聯不能同時發生時,用一條虛線連接這兩個關聯,并且虛線的中間帶有{OR}關鍵字。

或關聯以及前面介紹的其他關聯都涉及了多個類。但是,有時候參與關聯的對象屬于同一個類,這種關聯被稱為反身關聯。例如,不同的飛機場通過航線關聯起來,用Airport類表示機場,那么Airport對象之間的關聯關系就只涉及了一個類。
當關聯關系存在于兩個不同的類之間時,關聯直線從其中的一個類連接到另一個類。而如果參與關聯的對象屬于同一個類,那么關聯直線的起點和終點都是該類,如下圖所示。

上圖中,該關聯只涉及一個Airport類。反身關聯通常要使用角色名稱。在二元關聯中描述一個關聯時需要使用類名稱,但在反身關聯中只使用類表達關聯的意義可能比較模糊,而使用角色名則會更清晰一些。
4.4.4 聚合關系
聚合(Aggregation)關系是在關聯之上進一步的緊密耦合,用來表明一個類實際上不擁有但可能共享另一個類的對象。聚合關系是一種特殊的關聯關系,它表示整體與部分的關系,且部分可以離開整體而單獨存在。在聚合關系中,一個類是整體,它由一個或者多個部分類組成。當整體類不存在時部分類仍能存在,但是當它們聚集在一起時就用于組成相應的整體類。例如,車和輪胎就可以看作是聚合關系,車為整體,輪胎為部分,輪胎離開車后仍然可以存在。
在表示聚合關系時,需要在關聯實線的連接整體類那一端添加一個菱形,如下圖所示演示了一個簡單的聚合關系。

在上圖中,CPU類和Monitor類與Computer類之間的關系遠比關聯關系更強。CPU類和Monitor類都可以單獨存在,但當它們組成Computer類時,就會變為整個計算機的組成部分。
提示
由于聚合關聯的部分類可以獨立存在,這意味著當整體類銷毀時,部分類仍可以存在。如果部分類被銷毀,整體類也將能夠繼續存在。
4.4.5 組合關系
在類的眾多關系中,再加強一步的耦合是組合關系,組合關系也是一種特殊的關聯關系,在某種情況下,也可以說它是一種特殊的聚合關系。組合關系是比聚合關系還要強的關系,它要求普通的聚合關系中代表整體的對象負責代表部分的對象的生命周期。
組合關系和聚合關系很相似,都是整體與部分的關聯關系,但是它們之間的不同之處在于部分不能離開整體而單獨存在,當整體類被銷毀時,部分類將同時被銷毀。例如,公司和部門是整體和部分的關系,沒有公司,就不存在部門。
組合關系所表達的內涵是為組成類的內在部分建模。表示組成關系的符號與聚合關系類似,但是端末的菱形是實心的。如下圖所示為一個簡單的組合關系示例圖。

上圖中代表數據庫的整體類DBEmployee由表TableEmployee和表Employee組成,這些關聯使用組合關系表示。如果數據庫不存在了,數據庫中的表也就不存在了。
組合關系還可以進行嵌套,如下圖所示。

上圖中添加了Record類,可以將該類作為TableEmployee的部分類。該圖也說明表TableEmployee中有0個或者0個以上的記錄,也表達了記錄不能離開表單獨存在這一客觀情況。
- Learn ECMAScript(Second Edition)
- Learning RabbitMQ
- Building Mobile Applications Using Kendo UI Mobile and ASP.NET Web API
- Building a Recommendation Engine with Scala
- JSP開發案例教程
- SAP BusinessObjects Dashboards 4.1 Cookbook
- 小學生C++創意編程(視頻教學版)
- Instant Nancy Web Development
- HTML5秘籍(第2版)
- Go語言開發實戰(慕課版)
- jQuery for Designers Beginner's Guide Second Edition
- 貫通Tomcat開發
- JavaScript編程精解(原書第2版)
- 游戲設計的底層邏輯
- Raspberry Pi By Example