雙向關聯:設計模式
C1-C2:指雙方都知道對方的存在,均可以調用對方的公共屬性和方法。設計
在GOF的設計模式書上是這樣描述的:雖然在分析階段這種關係是適用的,但咱們以爲它對於描述設計模式內的類關係來講顯得太抽象了,由於在設計階段關聯關係必須被映射爲對象引用或指針。對象引用自己就是有向的,更適合表達咱們所討論的那種關係。因此這種關係在設計的時候比較少用到,關聯通常都是有向的。3d
代碼以下:指針
class C1 { public: C2 * theC2; }; class C2 { public: C1 * theC1; };
雙向關聯在代碼中的表現爲雙方都擁有對方的一個指針,固然也能夠是引用或者是值。對象
單向關聯:blog
C1→C2:表示相識關係,指C1知道C2,C1能夠調用C2的公共屬性和方法。沒有生命期的依賴,通常表示爲一種引用。繼承
代碼以下:接口
class C1 { public: C2 * theC2; }; class C2 { };
單向關聯的代碼就表現爲C1有C2的指針,而C2對C1一無所知。ip
自身關聯:ci
本身引用本身,帶着一個本身的引用。
代碼以下:
class C1 { public: C1 * theC1; };
就是在內部有着一個自身的引用。
當類之間有總體-部分關係的時候,咱們就可使用組合或者聚合。
聚合:
表示C1聚合C2,可是C2能夠離開C1而獨立存在(獨立存在的意思是在某個應用的問題域中這個類的存在有意義),這句話怎麼理解,請看下面組合裏的解釋。
代碼以下:
class C1 { public: C2 theC2; }; class C2 { };
組合:
通常是實心菱形加實線箭頭表示,如上圖所示,表示的是C2被C1組合,並且C2不能離開C1而獨立存在,但這是視問題域而定的。例如在關心汽車的領域裏,輪胎是必定要組合在汽車類中的,由於它離開了汽車就沒有意義了;可是在賣輪胎的店鋪業務裏,就算輪胎離開了汽車,它也是有意義的,這就能夠用聚合了。在《敏捷開發》中還說到,A組合B,則A須要知道B的生存週期,便可能A負責生成或者釋放B,或者A經過某種途徑知道B的生成和釋放。
代碼以下:
class C1 { public: C2 theC2; }; class C2 { };
能夠看到,代碼和聚合是同樣的。具體如何區別,可能就只能用語義來區分了。
指C1可能要用到C2的一些方法,也能夠這樣說,要完成C1裏的全部功能,必定要有C2的方法協助才行。C1依賴於C2的定義,通常是在C1類的頭文件中包含了C2的頭文件。
注意,要避免雙向依賴。通常來講,不該該存在雙向依賴。
代碼以下:
// C1.h #include <C2.h>
class C1 { }; // C2.h #include <C1.h> class C2 { };
在形式上通常是A中的某個方法把B的對象做爲參數使用(假設A依賴於B)。以下:
#include "B.h" class A { void func(B & b); };
那依賴和聚合\組合、關聯等有什麼不一樣呢?
關聯是類之間的一種關係,例如老師教學生,老公和老婆,水壺裝水等就是一種關係。這種關係是很是明顯的,在問題領域中經過分析直接就能得出。
依賴是一種弱關聯,只要一個類用到另外一個類,可是和另外一個類的關係不是太明顯的時候(能夠說是"uses"了那個類),就能夠把這種關係當作是依賴,依賴也可說是一種偶然的關係,而不是必然的關係,就是"我在某個方法中偶然用到了它,但在現實中我和它並沒多大關係"。例如我和錘子,我和錘子原本是不要緊的,但在有一次要釘釘子的時候,我用到了它,這就是一種依賴,依賴錘子完成釘釘子這件事情。
組合是一種總體-部分的關係,在問題域中這種關係很明顯,直接分析就能夠得出的。例如輪胎是車的一部分,樹葉是樹的一部分,手腳是身體的一部分這種的關係,很是明顯的總體-部分關係。
上述的幾種關係(關聯、聚合/組合、依賴)在代碼中可能以指針、引用、值等的方式在另外一個類中出現,不拘於形式,但在邏輯上他們就有以上的區別。
這裏還要說明一下,所謂的這些關係只是在某個問題域纔有效,離開了這個問題域,可能這些關係就不成立了,例如可能在某個問題域中,我是一個木匠,須要拿着錘子去幹活,可能整個問題的描述就是我拿着錘子怎麼釘桌子,釘椅子,釘櫃子;既然整個問題就是描述這個,我和錘子就不只是偶然的依賴關係了,我和錘子的關係變得很是的緊密,可能就上升爲組合關係(讓我忽然想起武俠小說的劍不離身,劍亡人亡...)。這個例子可能有點荒謬,但也是爲了說明一個道理,就是關係和類同樣,它們都是在一個問題領域中才成立的,離開了這個問題域,他們可能就不復存在了。
泛化關係:若是兩個類存在泛化的關係時就使用,例如父和子,動物和老虎,植物和花等。
代碼以下:
#include "C1.h" class C2 : public C1 { };
這裏再說一下重複度,其實看完了上面的描述以後,咱們應該清楚了各個關係間的關係以及具體對應到代碼是怎麼樣的,所謂的重複度,也只不過是上面的擴展,例如A和B有着"1對多"的重複度,那在A中就有一個列表,保存着B對象的N個引用,就是這樣而已。
_____________________________________________________________
在UNL建模中,對類圖上出現元素的理解是相當重要的。開發者必須理解如何將類圖上出現的元素轉換到Java中。以Java爲表明結合網上的一些實例,下面是我的一些基本收集與總結:
基本元素符號:
類包含三個組成部分。第一個是Java中定義的類名,第二個是屬性(attributes),第三個是該類提供的方法。屬性和操做以前可附加一個可見性修飾符,加號(+)表示具備公共可見性。減號(-)表示私有可見性。#號表示受保護的可見性。省略這些修飾符表示具備Package(包)級別的可見性。若是屬性或操做具備下劃線,代表它是靜態的。在操做中,可同時列出它接受的參數,以及返回類型,以下圖所示:
包是一種常規用途的組合機制。UML中的一個包直接對應於Java中的一個包,在Java中,一個包可能含有其餘包、類或者同時含有這二者。進行建模時,你一般擁有邏輯性的包,它主要用於對你的模型進行組織。你還會擁有物理性的包,它直接轉換成系統中的Java包。每一個包的名稱對這個包進行了惟一性的標識。
接口是一系列操做的集合,它指定了一個類所提供的服務,它直接對應於Java中的一個接口類型。接口便可用下面的那個圖標表示(上面一個圓圈符號,圓圈符號下面是接口名,中間是直線,直線下面是方法名),也可由附加了<<interface>>的一個標準類來表示。一般,根據接口在類圖上的樣子,就能知道與其餘類的關係。
關係:
實體之間一個"使用"關係暗示一個實體的規範發生變化後,可能影響依賴於它的其餘實例。更具體地說,它可轉換爲對不在實例做用域內的一個類或對象的任何類型的引用。其中包括一個局部變量,對經過方法調用而得到的一個對象的引用(以下例所示),或者對一個類的靜態方法的引用(同時不存在那個類的一個實例)。也可利用"依賴"來表示包和包之間的關係。因爲包中含有類,因此你可根據那些包中的各個類之間的關係,表示出包和包的關係。
實體之間的一個結構化關係代表對象是相互鏈接的。箭頭是可選的,它用於指定導航能力。若是沒有箭頭,暗示是一種雙向的導航能力。在Java中,關聯轉換爲一個實例做用域的變量,就像圖E的"Java"區域所展現的代碼那樣。可爲一個關聯附加其餘修飾符。多重性(Multiplicity)修飾符暗示着實例之間的關係。在示範代碼中,Employee能夠有0個或更多的TimeCard對象。可是,每一個TimeCard只從屬於單獨一個Employee。
聚合是關聯的一種形式,表明兩個類之間的總體/局部關係。聚合暗示着總體在概念上處於比局部更高的一個級別,而關聯暗示兩個類在概念上位於相同的級別。聚合也轉換成Java中的一個實例做用域變量。
關聯和聚合的區別純粹是概念上的,並且嚴格反映在語義上。聚合還暗示着實例圖中不存在迴路。換言之,只能是一種單向關係。
合成是聚合的一種特殊形式,暗示"局部"在"總體"內部的生存期職責。合成也是非共享的。因此,雖然局部不必定要隨總體的銷燬而被銷燬,但總體要麼負責保持局部的存活狀態,要麼負責將其銷燬。
局部不可與其餘總體共享。可是,總體可將全部權轉交給另外一個對象,後者隨即將承擔生存期職責。Employee和TimeCard的關係或許更適合表示成"合成",而不是表示成"關聯"。
泛化表示一個更泛化的元素和一個更具體的元素之間的關係。泛化是用於對繼承進行建模的UML元素。在Java中,用extends關鍵字來直接表示這種關係。
實例關係指定兩個實體之間的一個合同。換言之,一個實體定義一個合同,而另外一個實體保證履行該合同。對Java應用程序進行建模時,實現關係可直接用implements關鍵字來表示。