### 一、什么是組合復用原則
組合復用原則也叫合成/聚合復用原則(CARP),就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分;新的對象通過向這些對象的委派達到復用已有功能的目的。
**這個原則的簡短表述就是:要盡量使用組合,盡量不要使用繼承。**
### 二、實現復用的兩種方式
在面向對象的設計里,有兩種基本的方法可以在不同的環境中復用已有的設計和實現,即通過組合或通過繼承。
**組合**
由于組合可以將已有的對象納入到新對象中,使之成為新對象的一部分,因此新對象可以調用已有對象的功能,這樣做有下面的好處:
- 新對象存取成分對象的唯一方法是通過成分對象的接口。
- 這種復用是黑箱復用,因為成分對象的內部細節是新對象所看不見的。
- 這種復用支持包裝。
- 這種復用所需要的依賴較少。
- 每一個新的類可以將焦點集中到一個任務上。
- 這種復用可以在運行時間動態進行,新對象可以動態的引用與成分對象類型相同的對象。
組合復用的缺點就是用組合復用建造的系統會有較多的對象需要管理。
**繼承**
組合幾乎可以用到任何環境中去,但是繼承只能用到一些環境中。
繼承復用通過擴展一個已有對象的實現來得到新的功能,基類明顯的捕獲共同的屬性和方法,而子類通過增加新的屬性和方法來擴展超類的實現。
繼承的優點:
新的實現比較容易,因為基類的大部分功能都可以通過繼承自動的進入子類。
修改或擴展繼承而來的實現較為容易。
繼承的缺點:
- 繼承復用破壞了包裝,因為繼承超類的的實現細節暴露給子類。由于超類的內部細節常常對子類是透明的,因此這種復用是透明的復用,又稱“白箱”復用。
- 如果超類的實現發生改變,那么子類的實現也不得不發生改變。因此,當一個基類發生改變時,這種改變就會像水中投入石子引起的水波一樣,將變化一圈又一圈的傳導到一級又一級的子類,使設計師不得不相應地改變這些子類,以適應超類的變化。
- 從超類繼承而來的實現是靜態的,不可能在運行時間內發生改變,因此沒有足夠的靈活性。
### 三、使用組合還是繼承
按照組合復用原則我們應該首選組合,然后才是繼承,使用繼承時應該嚴格的遵守里氏替換原則,必須滿足“Is-A”的關系是才能使用繼承,而組合卻是一種“Has-A”的關系。導致錯誤的使用繼承而不是使用組合的一個重要原因可能就是錯誤的把“Has-A”當成了“Is-A”。
下面看一個例子:

人被繼承到雇員,學生,經理子類。而實際上,雇員、學生和經理分別描述一種角色,而人可以同時有幾種不同的角色。比如,一個人既然是經理了就一定是雇員,使用繼承來實現角色,則只能使用每一個人具有一種角色,這顯然是不合理的。錯誤的原因就是把角色的等級結構和人的等級結構混淆起來,把Has-A的關系誤認為是Is-A的關系,通過下面的改正就可以正確的做到這一點。

從上圖可以看出,每一個人都可以有一個以上的角色,所以一個人可以同時是雇員又是經理。從這個例子可以看出,當一個類是另一個類的角色時,不應該使用繼承描述這種關系。
- 前言
- 設計原則(一)"開-閉"原則(OCP)
- 設計原則(二)里氏替換原則(LSP)
- 設計原則(三)組合復用原則
- 設計原則(四)依賴倒置原則(DIP)
- 設計模式(一)簡單工廠模式
- 設計模式(二)工廠方法模式
- 設計模式(三)抽象工廠模式
- 設計模式(四)單例模式
- 設計模式(五)創建者模式(Builder)
- 設計模式(六)原型模式
- 設計模式(七)門面模式(Facade Pattern 外觀模式)
- 設計模式(八)橋梁模式(Bridge)
- 設計模式(九)裝飾模式(Decorator)
- 設計模式(十)適配器模式
- 設計模式(十一)策略模式
- 設計模式(十二)責任鏈模式
- 設計模式之UML(一)類圖以及類間關系(泛化 、實現、依賴、關聯、聚合、組合)
- 設計模式之橋梁模式和策略模式的區別