談談類之間的關聯關係與依賴關係
原文:http://www.cnblogs.com/iyangyuan/archive/2013/06/16/3138463.html
對於很多剛剛接觸UML的童鞋,可能會對類之間的關聯與依賴關係不太理解,今天小菜就淺薄的講一下。
這塊的確是有點亂,不過小菜突然找到了一個比較好的切入點,拿出來分享一下。
接觸過設計模式的讀者,會經常看到這樣的場景:在例項化A類的時候,需要B類作為構造方法的引數,這說明A類需要持有一個B類的引用。比如代理模式、裝飾模式等,都會這樣做。例如Java中的IO流採用的就是裝飾模式,所以我們會經常看到這樣的語句:new BufferInputStream(new FileInputStream("c:\\1.db"));
這種持有引用,就是簡單的關聯關係。在程式碼中表現為:在A類中有一個成員變數,變數的型別是B類,A類中持有了B類的引用,就說明A類和B類發生了關聯關係。
用UML圖表示如下:
稍加說明,由於是A類持有B類的引用,因此關聯是從A類中發出的(由A類引起),因此箭頭要從A類指向B類。
通常情況下,這種簡單的單向關聯就夠用了,但是關聯關係主要還是應用在資料庫設計中。
在資料庫設計中,無論是一對一、一對多、多對多,都不是單向的。
從表的角度分析,它們均可以從任意一端確定另一端。就拿一對多來說,有了one端的主鍵,可以根據many端表的外來鍵查出many端資料;有了many端外來鍵,可以根據one端表的主鍵查出one端資料。
從實體類的角度分析,同樣可以從任意一端確定另一端。還是拿一對多來說,one端的實體類會持有一個many端的引用集合,例如private Set<B> bs;,查詢到了one端,可以直接從這個集合中讀取many端;many端的實體類會持有一個one端的引用,例如private A a;,查詢到了many端,可以直接從這個引用確定每一個many端的one端。
這樣一來,就成了雙向關聯,用UML畫關聯關係的時候,兩邊都要加箭頭,這樣太難看,索性就都不加了。
例如部門實體類和員工實體類的關係,就可以這樣表示:
由於是資料庫實體類間的關聯關係,因此還要加上數量關係,1代表one端,0..n代表many端,說明一個部門可以有多個員工,但一個員工只能屬於一個部門,通過UML圖描述了一對多。
這個才是關聯關係典型的應用。
不得不提的是,關聯關係還可以細分為聚合和組合(二者的具體概念讀者自行搜尋)。
小菜發現聚合、組合可以從另一個角度去理解。
先說說聚合,它是一種弱關聯,大概意思就是整體和部分可以獨立存在。如果我們換個角度,可以看成是資料庫的級聯操作。
就拿小組和組員來說,刪除某個小組的時候,把該組的組員也刪除,這顯然是不科學的,因為小組和組員是一種弱關聯,小組可以擁有任意一個組員,一個組員也可以去任意一個小組,這個小組不存在了,可以去另一個小組,它們沒有必然的關聯,可以稱為聚合。
因此,我們在設計資料庫的時候,往往不會設定級聯刪除,也就是說,刪除小組時不會刪除組員。
UML圖表示如下:
空心菱形表示聚合,指向one端。
再說說組合,組合是一種強關聯,大概意思是整體和部分不可分割,不能獨立存在。同樣從級聯操作理解。
就拿學生和學生證來說,假如某個學生退學,不再屬於這個學校,那麼可以考慮將該學生資訊刪除,刪除的時候,學生對應的學生證資訊也會被刪除,在此處可以加級聯刪除。因為學生證屬於某個學生專有的資訊,學生不存在了,學生證又不能讓他人使用,因此是一種強關聯,可以稱為組合。
UML圖表示如下:
最後要談的是依賴關係。
假如A類的某個方法中,使用了B類,那麼就說A類依賴於B類,它們是依賴關係。
A類的某個方法使用B類,可能是方法的引數是B類,也可能是在方法中獲得了一個B類例項。但無論是哪種情況,B類在A類中都是以區域性變數的形式存在的。
因此,A類中有B型別的區域性變數,就說A類依賴於B類。
UML圖表示如下:
虛線箭頭表示依賴,箭頭指向被依賴的類。
綜上,有一個簡單的判斷原則:某個類以成員變數的形式出現在另一個類中,二者是關聯關係;某個類以區域性變數的形式出現在另一個類中,二者是依賴關係。
注意:本文為了方便講解,一直是拿類當例子,這並不是一種好的設計思維。實際開發中,為了更好的實現"開-閉原則",一般都是定義介面,依賴於介面,依賴於抽象,而不是根據具體程式設計,希望讀者不要被小菜誤導!!