面向?qū)ο笤O(shè)計(jì)原則之合成復(fù)用原則

合成復(fù)用原則又稱為組合/聚合復(fù)用原則(Composition/Aggregate Reuse Principle, CARP)企巢,其定義如下:

合成復(fù)用原則(Composite Reuse Principle, CRP):盡量使用對象組合病游,而不是繼承來達(dá)到復(fù)用的目的。

合成復(fù)用原則就是在一個(gè)新的對象里通過關(guān)聯(lián)關(guān)系(包括組合關(guān)系和聚合關(guān)系)來使用一些已有的對象讥电,使之成為新對象的一部分;新對象通過委派調(diào)用已有對象的方法達(dá)到復(fù)用功能的目的。簡言之:

復(fù)用時(shí)要盡量使用組合/聚合關(guān)系(關(guān)聯(lián)關(guān)系)馋贤,少用繼承

在面向?qū)ο笤O(shè)計(jì)中畏陕,可以通過兩種方法在不同的環(huán)境中復(fù)用已有的設(shè)計(jì)和實(shí)現(xiàn)配乓,即通過組合/聚合關(guān)系或通過繼承,但首先應(yīng)該考慮使用組合/聚合蹭秋,組合/聚合可以使系統(tǒng)更加靈活扰付,降低類與類之間的耦合度,一個(gè)類的變化對其他類造成的影響相對較少仁讨;其次才考慮繼承羽莺,在使用繼承時(shí),需要嚴(yán)格遵循里氏代換原則洞豁,有效使用繼承會(huì)有助于對問題的理解盐固,降低復(fù)雜度荒给,而濫用繼承反而會(huì)增加系統(tǒng)構(gòu)建和維護(hù)的難度以及系統(tǒng)的復(fù)雜度,因此需要慎重使用繼承復(fù)用刁卜。

通過繼承來進(jìn)行復(fù)用的主要問題在于繼承復(fù)用會(huì)破壞系統(tǒng)的封裝性志电,因?yàn)槔^承會(huì)將基類的實(shí)現(xiàn)細(xì)節(jié)暴露給子類,由于基類的內(nèi)部細(xì)節(jié)通常對子類來說是可見的蛔趴,所以這種復(fù)用又稱“白箱”復(fù)用挑辆,如果基類發(fā)生改變,那么子類的實(shí)現(xiàn)也不得不發(fā)生改變孝情;從基類繼承而來的實(shí)現(xiàn)是靜態(tài)的鱼蝉,不可能在運(yùn)行時(shí)發(fā)生改變,沒有足夠的靈活性箫荡;而且繼承只能在有限的環(huán)境中使用(如類沒有聲明為不能被繼承)魁亦。

由于組合或聚合關(guān)系可以將已有的對象(也可稱為成員對象)納入到新對象中,使之成為新對象的一部分羔挡,因此新對象可以調(diào)用已有對象的功能洁奈,這樣做可以使得成員對象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)對于新對象不可見,所以這種復(fù)用又稱為“黑箱”復(fù)用绞灼,相對繼承關(guān)系而言利术,其耦合度相對較低,成員對象的變化對新對象的影響不大镀赌,可以在新對象中根據(jù)實(shí)際需要有選擇性地調(diào)用成員對象的操作氯哮;合成復(fù)用可以在運(yùn)行時(shí)動(dòng)態(tài)進(jìn)行,新對象可以動(dòng)態(tài)地引用與成員對象類型相同的其他對象商佛。

一般而言喉钢,如果兩個(gè)類之間是“Has-A”的關(guān)系應(yīng)使用組合或聚合,如果是“Is-A”關(guān)系可使用繼承良姆。"Is-A"是嚴(yán)格的分類學(xué)意義上的定義肠虽,意思是一個(gè)類是另一個(gè)類的"一種";而"Has-A"則不同玛追,它表示某一個(gè)角色具有某一項(xiàng)責(zé)任税课。

下面通過一個(gè)簡單實(shí)例來加深對合成復(fù)用原則的理解:

Sunny軟件公司開發(fā)人員在初期的CRM系統(tǒng)設(shè)計(jì)中,考慮到客戶數(shù)量不多痊剖,系統(tǒng)采用MySQL作為數(shù)據(jù)庫韩玩,與數(shù)據(jù)庫操作有關(guān)的類如CustomerDAO類等都需要連接數(shù)據(jù)庫,連接數(shù)據(jù)庫的方法getConnection()封裝在DBUtil類中陆馁,由于需要重用DBUtil類的getConnection()方法找颓,設(shè)計(jì)人員將CustomerDAO作為DBUtil類的子類,初始設(shè)計(jì)方案結(jié)構(gòu)如圖1所示:

圖1 初始設(shè)計(jì)方案結(jié)構(gòu)圖.png

隨著客戶數(shù)量的增加,系統(tǒng)決定升級為Oracle數(shù)據(jù)庫适贸,因此需要增加一個(gè)新的OracleDBUtil類來連接Oracle數(shù)據(jù)庫,由于在初始設(shè)計(jì)方案中CustomerDAO和DBUtil之間是繼承關(guān)系闯参,因此在更換數(shù)據(jù)庫連接方式時(shí)需要修改CustomerDAO類的源代碼彪蓬,將CustomerDAO作為OracleDBUtil的子類寸莫,這將違反開閉原則〉刀【當(dāng)然也可以修改DBUtil類的源代碼膘茎,同樣會(huì)違反開閉原則〉方迹】

現(xiàn)使用合成復(fù)用原則對其進(jìn)行重構(gòu)辽狈。

根據(jù)合成復(fù)用原則,我們在實(shí)現(xiàn)復(fù)用時(shí)應(yīng)該多用關(guān)聯(lián)呛牲,少用繼承。因此在本實(shí)例中我們可以使用關(guān)聯(lián)復(fù)用來取代繼承復(fù)用驮配,重構(gòu)后的結(jié)構(gòu)如圖2所示:

圖2 重構(gòu)后的結(jié)構(gòu)圖.png

在圖2中娘扩,CustomerDAO和DBUtil之間的關(guān)系由繼承關(guān)系變?yōu)殛P(guān)聯(lián)關(guān)系,采用依賴注入的方式將DBUtil對象注入到CustomerDAO中壮锻,可以使用構(gòu)造注入琐旁,也可以使用Setter注入。如果需要對DBUtil的功能進(jìn)行擴(kuò)展猜绣,可以通過其子類來實(shí)現(xiàn)灰殴,如通過子類OracleDBUtil來連接Oracle數(shù)據(jù)庫。由于CustomerDAO針對DBUtil編程掰邢,根據(jù)里氏代換原則牺陶,DBUtil子類的對象可以覆蓋DBUtil對象,只需在CustomerDAO中注入子類對象即可使用子類所擴(kuò)展的方法辣之。例如在CustomerDAO中注入OracleDBUtil對象掰伸,即可實(shí)現(xiàn)Oracle數(shù)據(jù)庫連接,原有代碼無須進(jìn)行修改怀估,而且還可以很靈活地增加新的數(shù)據(jù)庫連接方式狮鸭。

文章轉(zhuǎn)載自 —— 面向?qū)ο笤O(shè)計(jì)原則之合成復(fù)用原則

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市多搀,隨后出現(xiàn)的幾起案子歧蕉,更是在濱河造成了極大的恐慌,老刑警劉巖康铭,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惯退,死亡現(xiàn)場離奇詭異,居然都是意外死亡麻削,警方通過查閱死者的電腦和手機(jī)蒸痹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門春弥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叠荠,你說我怎么就攤上這事匿沛。” “怎么了榛鼎?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵逃呼,是天一觀的道長。 經(jīng)常有香客問我者娱,道長抡笼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任黄鳍,我火速辦了婚禮推姻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘框沟。我一直安慰自己藏古,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布忍燥。 她就那樣靜靜地躺著拧晕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梅垄。 梳的紋絲不亂的頭發(fā)上厂捞,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音队丝,去河邊找鬼靡馁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛炭玫,可吹牛的內(nèi)容都是我干的奈嘿。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼吞加,長吁一口氣:“原來是場噩夢啊……” “哼裙犹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起衔憨,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤叶圃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后践图,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掺冠,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了德崭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斥黑。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖眉厨,靈堂內(nèi)的尸體忽然破棺而出锌奴,到底是詐尸還是另有隱情,我是刑警寧澤憾股,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布鹿蜀,位于F島的核電站,受9級特大地震影響服球,放射性物質(zhì)發(fā)生泄漏茴恰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一斩熊、第九天 我趴在偏房一處隱蔽的房頂上張望往枣。 院中可真熱鬧,春花似錦座享、人聲如沸婉商。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盯捌,卻和暖如春淳衙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饺著。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工箫攀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幼衰。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓靴跛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親渡嚣。 傳聞我的和親對象是個(gè)殘疾皇子梢睛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350