類間關係
在類圖中,除了需要描述單獨的類的名稱、屬性和操作外,我們還需要描述類之間的聯絡,因為沒有類是單獨存在的,它們通常需要和別的類協作,創造比單獨工作更大的語義。在UML類圖中,關係用類框之間的連線來表示,連線上和連線端頭處的不同修飾符表示不同的關係。類之間的關係有繼承(泛化)、關聯、聚合和組合。
(1)繼承:指的是一個類(稱為子類)繼承另外的一個類(稱為基類)的功能,並增加它自己的新功能的能力,繼承是類與類之間最常見的關係。類圖中繼承的表示方法是從子類拉出一條閉合的、單鍵頭(或三角形)的實線指向基類。例如,圖3.2給出了MFC中
CObject類和選單類CMenu的繼承關係。
圖3.2 類的繼承
類的繼承在C++中呈現為:
class B { }
class A : public B{ }
(2)關聯:指的是模型元素之間的一種語義聯絡,是類之間的一種很弱的聯絡。關聯可以有方向,可以是單向關聯,也可以是雙向關聯。可以給關聯加上關聯名來描述關聯的作用。關聯兩端的類也可以以某種角色參與關聯,角色可以具有多重性,表示可以有多少個物件參與關聯。可以通過關聯類進一步描述關聯的屬性、操作以及其他資訊。關聯類通過一條虛線與關聯連線。對於關聯可以加上一些約束,以加強關聯的含義。
關聯在C++中呈現為:
class A{...}
class B{ ...}
A::Function1(B &b) //或A::Function1(B b) //或A::Function1(B *b)
即一個類作為另一個類方法的引數。
(3)聚合:指的是整體與部分的關係。通常在定義一個整體類後,再去分析這個整體類的組成結構。從而找出一些組成類,該整體類和組成類之間就形成了聚合關係。例如一個航母編隊包括海空母艦、驅護艦艇、艦載飛機及核動力攻擊潛艇等。需求描述中“包含”、“組成”、“分為…部分”等詞常意味著聚合關係。
(4)組合:也表示類之間整體和部分的關係,但是組合關係中部分和整體具有統一的生存期。一旦整體物件不存在,部分物件也將不存在。部分物件與整體物件之間具有共生死的關係。
聚合和組合的區別在於:聚合關係是“has-a”關係,組合關係是“contains-a”關係;聚合關係表示整體與部分的關係比較弱,而組合比較強;聚合關係中代表部分事物的物件與代表聚合事物的物件的生存期無關,一旦刪除了聚合物件不一定就刪除了代表部分事物的物件。組合中一旦刪除了組合物件,同時也就刪除了代表部分事物的物件。
我們用淺顯的例子來說明聚合和組合的區別。“國破家亡”,國滅了,家自然也沒有了,“國”和“家”顯然也是組合關係。而相反的,計算機和它的外設之間就是聚合關係,因為它們之間的關係相對鬆散,計算機沒了,外設還可以獨立存在,還可以接在別的計算機上。在聚合關係中,部分可以獨立於聚合而存在,部分的所有權也可以由幾個聚合來共享,比如印表機就可以在辦公室內被廣大同事共用。
在C++語言中,從實現的角度講,聚合可以表示為:
class A {...}
class B { A* a; .....}
即類B包含類A的指標;(轉者注:即B類擁有A類的引用)
而組合可表示為:
class A{...}
class B{ A a; ...}
即類B包含類A的物件。(轉者注:即B類擁有一個A類物件,或可以說B類裡的A類是B類唯一擁有的[最簡單點的說就是B類裡的這個A類只屬於B類])
準確的UML類圖中用空心和實心菱形對聚合和組合進行了區分。
圖3.4 聚合和組合
聚合,關聯,組合 是物件之間的三種關係。從某種意義上說,繼承是一種類的縱向關係,而聚合,關聯,組合是物件的橫向關係。
其關係強弱為 關聯<聚合<組合
關聯和聚合的區別主要在語義上,關聯的兩個物件之間一般是平等的,例如你是我的朋友,聚合則一般不是平等的,例如一個公司包含了很多員工,其實現上是差不多的。聚合和組合的區別則在語義和實現上都有差別,組合的兩個物件之間其生命期有很大的關聯,被組合的物件是在組合物件建立的同時或者建立之後建立,在組合物件銷燬之前銷燬。一般來說被組合物件不能脫離組合物件獨立存在,而且也只能屬於一個組合物件,例如一個文件的版本,必須依賴於文件的存在,也只能屬於一個文件。聚合則不一樣,被聚合的物件可以屬於多個聚合物件,例如一個員工可能可以屬於多個公司。
我想舉個通俗的例子。
你和你的心臟之間是composition關係(心臟只屬於自己)
你和你買的書之間是aggregation關係(書可能是別人的)
你和你的朋友之間是association關係
聚合與組合的區別:聚合∶分散的聚集到一起 組合∶幾個獨立部分組成的整體 由上可見,聚合就像將不同的水果放到一個玻璃果盤裡,玻璃果盤摔壞,並不影響水果。
1.例項化(依賴)
A將B作為區域性變數進行使用.
程式1
void A::foo()
{
B b;
b.SomeMethod();
}
2.關聯
A與B存在一定的關係. 這裡只考慮單向導航. 關聯在程式碼中有多種表現形式.
第一種, 作為引數:
程式2
void A::foo(B& b) // (B* b) or (B b)
{
b.SomeMethod();
}
第二種, 作為成員變數:
程式3
class A
{
public:
A(B& b)
{
b_ = b;
}
void foo()
{
b_.SomeMethod();
}
private:
B& b_; // B* b_
};
3.聚合
聚合是一種特殊的關聯, 聚合更明確指出聚合的主體具有整體-部分關係. 程式碼的表現形式見程式3.
4.組合
組合是一種特殊的聚合, 組合中的某個主體控制著另外一個主體的生命週期,而且他們還存在整體-部分關係.
程式4
class A
{
public:
A()
{
b_ = new B;
}
~A()
{
delete b_;
b_ = NULL;
}
void foo()
{
b_-> SomeMethod();
}
private:
B* b_;
};