繼承還是關聯?是個問題

2021-08-29 06:03:19 字數 2834 閱讀 1298

當我們的講物件導向或系統設計的老師又在課堂上向我們傳授在進行復用時「盡量使用合成/聚合,而不是使用繼承」的「定理」的時候,可能我們彷彿真的找到了問題的解決方法,但是這背後意味著什麼呢?我們為什麼需要這樣做呢?是否這是問題的最佳解決方案了呢?這一切的問題起源於乙個名為「合成聚合復用原則」的ood原則...

下面還是通過csdn上health king的專欄的一篇文章來進行講述吧!塗了顏色[ ]的是我自己做得注釋。

合成(composition)和聚合(aggregation)都是關聯(association)的特殊種類。聚合表示整體和部分的關係,表示「擁有」;合成則是一種更強的「擁有」,部分和整體的生命週期一樣。合成的新的物件完全支配其組成部分,包括它們的建立和湮滅等。乙個合成關係的成分物件是不能與另乙個合成關係共享的。

換句話說,合成是值的聚合(aggregation by value),而一般說的聚合是引用的聚合(aggregation by reference)。

[不過好像現在對合成和聚合不是太追究了,特別是在uml2.0裡面,所以這個問題我們知道就可以了]

簡短的說,合成-聚合復用原則(carp)是指:盡量使用合成/聚合,而不是使用繼承。[定理出現了]

在ood中,有兩種基本的辦法可以實現復用,一種是通過合成/聚合,另外一種就是通過繼承[當然還有好多擴充套件型的設計模式可以拿來用,例如最長見的decorator模式,這都是後話了]。通過合成/聚合的好處是:

----- 新物件訪問成分物件的唯一方法是通過成分物件的介面。 [恩,符合依賴倒轉原則,贊!]

----- 這種復用是黑箱復用,因為成分物件的內部細節是新物件所看不見的。 [降低了復用的複雜性]

----- 這種復用支援包裝。 [不知道是不是在說decorator模式呢!]

----- 這種復用所需的依賴較少。 [想要關聯誰,我就關聯誰,我的地盤我做主,哈哈]

----- 每乙個新的類可以將焦點集中在乙個任務上。 [可以將一些子任務分派的成分物件裡面,而本身只關心自己的任務,這也是設計乙個物件所要考慮的,每個物件都有自己的責任,他只需要把自己的責任做好就足夠了,不要去干涉其他的物件的責任,看來,我們的系統我們不需要多管閒事的物件]

----- 這種復用可以在執行時間內動態進行,新物件可以動態的引用與成分物件型別相同的物件。 [增加了復用的靈活性,對復用可以進行靈活的配置]

----- 作為復用手段可以應用到幾乎任何環境中去。 [這句話有一些不明白了?]

它的缺點就是系統中會有較多的物件需要管理。 [還是不能避免好的設計會帶來複雜性的問題]

通過繼承來進行復用的優點是:

-----新的實現較為容易,因為超類的大部分功能可以通過繼承的關係自動進入子類。

----- 修改和擴充套件繼承而來的實現較為容易。

通過繼承來實現復用的缺點是:

----- 繼承復用破壞包裝,因為繼承將超類的實現細節暴露給子類。由於超類的內部細節常常是對於子類透明的,所以這種復用是透明的復用, 又稱「白箱」復用。[但是有時這種透明,會代來不好的結果,可能有的時候我們只想去用乙個功能,而並不想弄清楚功能是怎麼實現的]

----- 如果超類發生改變,那麼子類的實現也不得不發生改變。[又是改變,但誰能避免改變呢,我們能唯一確定不變的就是改變]

----- 從超類繼承而來的實現是靜態的,不可能在執行時間內發生改變,沒有足夠的靈活性。

----- 繼承只能在有限的環境中使用。 [如果有乙個final類,再有本事,我們也不能繼承它,所以只能去用關聯了]

要正確的選擇合成/復用和繼承,必須透徹的理解黎克特制代換原則和coad法則。黎克特制代換原則前面學習過,coad法則由peter coad提出,總結了一些什麼時候使用繼承作為復用工具的條件。 [這個原則我認為是最重要的,它給我們面對「繼承還是關聯」問題時乙個更加細緻和合理指導,而不是象生搬硬套的定理一樣**我們的思維]只有當以下的coad條件全部被滿足時,才應當使用繼承關係:

----- 子類是超類的乙個特殊種類,而不是超類的乙個角色,也就是區分「has-a」和「is-a」。只有「is-a」關係才符合繼承關係,「has-a」關係應當用聚合來描述。 [這個問題看似簡單,但是實際上是很難分辨的,只有慢慢地積累才會變成「火眼金睛」]

----- 永遠不會出現需要將子類換成另外乙個類的子類的情況。如果不能肯定將來是否會變成另外乙個子類的話,就不要使用繼承。 [就像前面所說的,利用繼承進行復用是靜態的,所以執行時或者將來的改變是繼承的硬傷]

----- 子類具有擴充套件超類的責任,而不是具有置換調(override)或登出掉(nullify)超類的責任。如果乙個子類需要大量的置換掉超類的行為,那麼這個類就不應該是這個超類的子類。

----- 只有在分類學角度上有意義時,才可以使用繼承。不要從工具類繼承。[不要進行沒有意義的繼承,這一點來說我們還是很容易分辨的,只要你對設計還有那麼一點對「優美」的追求,就不會犯這個錯誤的]

錯誤的使用繼承而不是合成/聚合的乙個常見原因是錯誤的把「has-a」當成了「is-a」。「is-a」代表乙個類是另外乙個類的一種;「has-a」代表乙個類是另外乙個類的乙個角色,而不是另外乙個類的特殊種類。[下面的用例很不錯的,我們是不是一直在犯這個錯誤呢,反正我是一直在犯這個錯誤,快來看看吧]

我們看乙個例子。如果我們把「人」當成乙個類,然後把「雇員」,「經理」,「學生」當成是「人」的子類。這個的錯誤在於把「角色」的等級結構和「人」的等級結構混淆了。「經理」,「雇員」,「學生」是乙個人的角色,乙個人可以同時擁有上述角色。如果按繼承來設計,那麼如果乙個人是雇員的話,就不可能是經理,也不可能是學生,這顯然不合理。正確的設計是有個抽象類「角色」,「人」可以擁有多個「角色」(聚合),「雇員」,「經理」,「學生」是「角色」的子類。

另外乙個就是只有兩個類滿足黎克特制代換原則的時候,才可能是「is-a」關係。也就是說,如果兩個類是「has-a」關係,但是設計成了繼承,那麼肯定違反黎克特制代換原則。[黎克特制代換原則馬上就會講了,這幾天在忙著面試,時間總是有點不夠用...]

做還是不做,是個問題

妹妹的問題 如下 我gg要和我做那個,我很猶豫,他說現在做過的太多了。我相信他的話,但作為女生 方 面就得想多點,以後要是他不愛我怎麼辦?如 果再找別的男生,會不會因.個 而有什麼想法?但 我很愛他,不想讓他失望,我該怎麼辦呢?下面我們就這個問題進行分析 因為是妹妹提出的問題,所以以下的分析是站在妹...

週末收了房,是租還是住,是個問題

去年6月買房到上周末收房,整整14個月,謝天謝地,開發商還健在.這14個月從來不敢掉以輕心,終於,它沒有爛尾,沒有縮水,實在是業主之大幸,我們終於從給開發商裝孫子過度到了給物管裝孫子的新階段.買的時候4200rmb如今漲到了5000rmb,所謂的巨集觀調控似乎跟成都這地界沒多大關係.聽說某個朋友的朋...

ESX還是ESXi?這不再是個問題

曾經在vmsky論壇 個本人的文章 esx還是esxi,這是個問題 並引起一些 近日發現searcher在vmsky論壇發了篇帖子,題為esx還是esxi,這不再是個問題,見此 帖子中提到vmware正在積極宣傳esxi的好處,其內部培訓甚至用了upgrade esx到esxi這樣的字眼,說明esx...