合成復(fù)用原則是面向?qū)ο笤O(shè)計(jì)原則的 7 條原則中剩下的最后一條,下面我們將對其進(jìn)行詳細(xì)地介紹。
合成復(fù)用原則(Composite Reuse Principle,CRP)又叫組合/聚合復(fù)用原則(Composition/Aggregate Reuse Principle,CARP)。它要求在軟件復(fù)用時(shí),要盡量先使用組合或者聚合等關(guān)聯(lián)關(guān)系來實(shí)現(xiàn),其次才考慮使用繼承關(guān)系來實(shí)現(xiàn)。
如果要使用繼承關(guān)系,則必須嚴(yán)格遵循里氏替換原則。合成復(fù)用原則同里氏替換原則相輔相成的,兩者都是開閉原則的具體實(shí)現(xiàn)規(guī)范。
通常類的復(fù)用分為繼承復(fù)用和合成復(fù)用兩種,繼承復(fù)用雖然有簡單和易實(shí)現(xiàn)的優(yōu)點(diǎn),但它也存在以下缺點(diǎn)。
1. 繼承復(fù)用破壞了類的封裝性。因?yàn)槔^承會(huì)將父類的實(shí)現(xiàn)細(xì)節(jié)暴露給子類,父類對子類是透明的,所以這種復(fù)用又稱為“白箱”復(fù)用。
2. 子類與父類的耦合度高。父類的實(shí)現(xiàn)的任何改變都會(huì)導(dǎo)致子類的實(shí)現(xiàn)發(fā)生變化,這不利于類的擴(kuò)展與維護(hù)。
3. 它限制了復(fù)用的靈活性。從父類繼承而來的實(shí)現(xiàn)是靜態(tài)的,在編譯時(shí)已經(jīng)定義,所以在運(yùn)行時(shí)不可能發(fā)生變化。
采用組合或聚合復(fù)用時(shí),可以將已有對象納入新對象中,使之成為新對象的一部分,新對象可以調(diào)用已有對象的功能,它有以下優(yōu)點(diǎn)。
1.它維持了類的封裝性。因?yàn)槌煞謱ο蟮膬?nèi)部細(xì)節(jié)是新對象看不見的,所以這種復(fù)用又稱為“黑箱”復(fù)用。
2. 新舊類之間的耦合度低。這種復(fù)用所需的依賴較少,新對象存取成分對象的唯一方法是通過成分對象的接口。
3. 復(fù)用的靈活性高。這種復(fù)用可以在運(yùn)行時(shí)動(dòng)態(tài)進(jìn)行,新對象可以動(dòng)態(tài)地引用與成分對象類型相同的對象。
合成復(fù)用原則是通過將已有的對象納入新對象中,作為新對象的成員對象來實(shí)現(xiàn)的,新對象可以調(diào)用已有對象的功能,從而達(dá)到復(fù)用。
下面以汽車分類管理程序?yàn)槔齺斫榻B合成復(fù)用原則的應(yīng)用。
【例1】汽車分類管理程序。
分析:汽車按“動(dòng)力源”劃分可分為汽油汽車、電動(dòng)汽車等;按“顏色”劃分可分為白色汽車、黑色汽車和紅色汽車等。如果同時(shí)考慮這兩種分類,其組合就很多。圖 1 所示是用繼淨(jìng):關(guān)系實(shí)現(xiàn)的汽車分類的類圖。

圖1 用繼承關(guān)系實(shí)現(xiàn)的汽車分類的類圖
從圖 1 可以看出用繼承關(guān)系實(shí)現(xiàn)會(huì)產(chǎn)生很多子類,而且增加新的“動(dòng)力源”或者增加新的“顏色”都要修改源代碼,這違背了開閉原則,顯然不可取。但如果改用組合關(guān)系實(shí)現(xiàn)就能很好地解決以上問題,其類圖如圖 2 所示。

圖2 用組合關(guān)系實(shí)現(xiàn)的汽車分類的類圖
結(jié)合前幾節(jié)的內(nèi)容,我們一共介紹了 7 種設(shè)計(jì)原則,它們分別為開閉原則、里氏替換原則、依賴倒置原則、單一職責(zé)原則、接口隔離原則、迪米特法則和本節(jié)所介紹的合成復(fù)用原則。
這 7 種設(shè)計(jì)原則是軟件設(shè)計(jì)模式必須盡量遵循的原則,各種原則要求的側(cè)重點(diǎn)不同。其中,開閉原則是總綱,它告訴我們要對擴(kuò)展開放,對修改關(guān)閉;里氏替換原則告訴我們不要破壞繼承體系;依賴倒置原則告訴我們要面向接口編程;單一職責(zé)原則告訴我們實(shí)現(xiàn)類要職責(zé)單一;接口隔離原則告訴我們在設(shè)計(jì)接口的時(shí)候要精簡單一;迪米特法則告訴我們要降低耦合度;合成復(fù)用原則告訴我們要優(yōu)先使用組合或者聚合關(guān)系復(fù)用,少用繼承關(guān)系復(fù)用。