天天看點

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

本節書摘來自異步社群出版社《c++面向對象高效程式設計(第2版)》一書中的第2章,第2.24節,作者: 【美】kayshav dattatri,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

c++面向對象高效程式設計(第2版)

發現類并建立類之間的關系,是分析和設計過程中最重要的階段。

booch方法論在類之間使用兩種主要關系—— is-a關系和has-a關系。關系的完整清單如下:

關聯(association)

繼承(inheritance)(is-a)

聚集(aggregation)(has-a)

使用(using)

執行個體(instantiation)(模闆)

元類(metaclass)

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

圖2-6

關聯(association)用于分析的早期階段,最終會成為has-a、is-a或者“使用”關系。關聯是一個雙向關系,a的客戶可以達到b,而b的客戶也可以達到a(見圖2-7)。

關系兩端的數字代表基數(cardinality),每家銀行可以有0..n個客戶,而客戶可以在0..n家銀行中有賬号(見圖2-8)。

在這種關系中,a類的執行個體包含b類的執行個體(a “has-a”b)。這并不意味着一定是實體上的包含(physical containment)(通過值),也可以通過指針或引用包含。這種關系通常稱為“has-a”關系,也稱為聚集(aggregation),用于表示整體/部分關系(見圖2-9)。

如圖2-9所示,關系線上的标注表明了聚集的性質,線兩端的數字表示基數。

人可以有多個駕駛執照(不同國家、不同類型的駕駛執照等),也可能一個駕駛執照都沒有,這種情況用基數(0..n)表示。換而言之,人可以有0個或者多個駕駛執照。符号●說明“has-a”關系的源頭。該例中,一個person有一個(或多個)drivinglicense。在給定person對象的情況下,可以查找(或枚舉(enumerate)) person所擁有的drivinglicense。但是,在給定drivinglicense對象的情況下,不可能找到它所屬的person。這是因為“has-a”是單向關系,符号●表示關系的源頭。person類對象旁的數字1表明任何drivinglicense對象都隻屬于一個person。關系的名稱“持有”也标在圖2-9中。

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

圖2-8

“has-a”關系可以通過指針、引用或者甚至通過包含的對象來實作(見表2-2)。也就是說,“has-a”并不意味着每個person類對象在實體上都包含許多drivinglicense類對象(盡管也可能這樣實作)。

表2-2 has-a關系中基數的選擇

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

“has-a”關系和“is-a”關系可以說是類之間最常用的關系。本書很多地方都使用has-a關系來表示類之間某些類型的包含關系。注意,“has-a”是一個通用術語,它的含義很多。例如,多人共同擁有度假屋,就可以表示為person和vacationhome之間的“has-a”關系。

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

圖2-10

類似地,公司雇傭職員也是這樣,仍然可以表示為employee和company之間的has-a關系(見圖2-10)。關系的名稱可以幫助我們更易了解關系的性質。

在職員—公司關系中,“為其工作”是從雇員的角度說明兩者的關系。如果給定employee類對象,我們可以找到她所工作的company(一個或多個);如果給定company類對象,為了找到employee,還需要另一種關系,如上圖的“聘用/雇傭”關系所示。這允許我們為給定的company類對象找到employee,這種雙向關系很常見。按照這樣的分析思路,請注意,不可能在任何時候都為特定的vacationhome找到所有與之關聯的person,因為在vacationhome到person之間不存在任何關系。從person到vacationhome之間存在“has-a”關系,而從vacationhome到person之間沒有這種關系。這就是“has-a”語句是單向關系的含義。在“共同擁有”關系中,person旁有一個基數(0..n)。這隻表明vacationhome可以同時被person(一人或多人)擁有。很明顯,person類對象在實體上并未包含vacationhome類對象在内。

再來看另一個“has-a”關系的例子。汽車有一個引擎,也就是說,car在實體上包含一個engine,這種情況可以用線末尾的實心方塊■表示,如圖2-11所示。另外,空心方塊□代表通過引用包含。

該例中,每個car類對象都有自己的engine類對象,這是真實的實體包含關系。而且,每個car都有1個engine類對象,如基數所示。每個engine有4個或更多的cylinder(汽缸),如圖2-11所示。

“has-a”關系表示一種生存期—控制的關系。被包含的engine類對象的生存期,由包含它的car類對象所控制。當建立car類對象時,也建立了engine類對象;當銷毀car類對象時,也銷毀了engine類對象(它是car的一部分)。

“使用”關系用于表示大多數的客戶—供應商關系。如果a類将b類作為a類成員函數的參數接收(或者從a類的成員函數傳回b類對象),并且和b類沒有任何其他類型的關聯,此時a類使用b類。如果b類用于a類的某個方法的實作中,也存在“使用”關系。空心圓圈○表示“使用”關系。

在圖2-12中,mailgateway(郵件網關)正在使用messagepacket(消息包)。記住,“使用”關系并不意味着“has-a”關系。如果mailgateway儲存messagepacket類對象(以某種形式),那麼mailgateway就有一個messagepacket,這就沒必要用“使用”關系。“has-a”關系是“使用”關系的超集,而且“has-a”比“使用”關系的功能更強大。

在問題的解決方案中,“使用”關系并不常見。

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

2.24.4 繼承關系(is-a)

“is-a”關系用于表示繼承,意味着從基類到派生類的一般-特殊關系(見圖2-13)。

manage(經理)是一個employee(雇員)。箭頭從派生類(manage)指向基類(employee)。在後面的章節中,将詳細介紹繼承。

大多數問題的解決方案都使用“has-a”和“is-a”關系的組合。“has-a”和“is-a”都是非常強大的關系,它們各有優缺點。設計者必須清楚地了解何時使用“is-a”關系,何時使用“has-a”關系。本書中有許多示例都闡述了兩者之間的差别。

大多數項目都不可能在一張紙上顯示出該項目涉及的所有類。為幫助分組(和模組化)類,我們使用了類範疇(class category)。類範疇通過包含在其中的類提供服務。類範疇有自己唯一的名稱(類似于類)。

《C++面向對象高效程式設計(第2版)》——2.24 Booch 中類的關系

圖2-14

要對整個系統進行進階描述,隻能用類範疇(見圖2-14)。類範疇的分解圖必須顯示其中包含的所有類,以及這些類之間的關系。

繼續閱讀