——探索設(shè)計(jì)模式系列之十五
Terrylee
,2006年5月
摘要:結(jié)構(gòu)型模式,顧名思義討論的是類(lèi)和對(duì)象的結(jié)構(gòu),它采用繼承機(jī)制來(lái)組合接口或?qū)崿F(xiàn)(類(lèi)結(jié)構(gòu)型模式),或者通過(guò)組合一些對(duì)象,從而實(shí)現(xiàn)新的功能(對(duì)象結(jié)構(gòu)型模式)。這些結(jié)構(gòu)型模式,它們?cè)谀承┓矫婢哂泻艽蟮南嗨菩裕屑?xì)推敲,側(cè)重點(diǎn)卻各有不同。本文試圖對(duì)這幾種結(jié)構(gòu)型模式做一個(gè)簡(jiǎn)單的小結(jié)。
主要內(nèi)容
1
.結(jié)構(gòu)型模式概述
2
.結(jié)構(gòu)型模式區(qū)別與比較
3
.對(duì)變化的封裝
結(jié)構(gòu)型模式概述
結(jié)構(gòu)型模式,顧名思義討論的是類(lèi)和對(duì)象的結(jié)構(gòu),它采用繼承機(jī)制來(lái)組合接口或?qū)崿F(xiàn)(類(lèi)結(jié)構(gòu)型模式),或者通過(guò)組合一些對(duì)象,從而實(shí)現(xiàn)新的功能(對(duì)象結(jié)構(gòu)型模式)。這些結(jié)構(gòu)型模式,它們?cè)谀承┓矫婢哂泻艽蟮南嗨菩裕屑?xì)推敲,側(cè)重點(diǎn)卻各有不同。
Adapter
模式通過(guò)類(lèi)的繼承或者對(duì)象的組合側(cè)重于轉(zhuǎn)換已有的接口;
Bridge
模式通過(guò)將抽象和實(shí)現(xiàn)相分離,讓它們可以分別獨(dú)立的變化,它強(qiáng)調(diào)的是系統(tǒng)沿著多個(gè)方向的變化;
Decorator
模式采用對(duì)象組合而非繼承的手法,實(shí)現(xiàn)了在運(yùn)行時(shí)動(dòng)態(tài)的擴(kuò)展對(duì)象功能的能力,它強(qiáng)調(diào)的是擴(kuò)展接口;
Composite
模式模糊了簡(jiǎn)單元素和復(fù)雜元素的概念,它強(qiáng)調(diào)的是一種類(lèi)層次式的結(jié)構(gòu);
Fa?ade
模式將復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)與客戶(hù)程序之間的依賴(lài)解耦,它側(cè)重于簡(jiǎn)化接口,更多的是一種架構(gòu)模式;
Flyweight
模式解決的是由于大量的細(xì)粒度對(duì)象所造成的內(nèi)存開(kāi)銷(xiāo)的問(wèn)題,它與
Fa?ade
模式恰好相反,關(guān)注的重點(diǎn)是細(xì)小的對(duì)象;
Proxy
模式為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪(fǎng)問(wèn),它注重于增加間接層來(lái)簡(jiǎn)化復(fù)雜的問(wèn)題。
結(jié)構(gòu)型模式區(qū)別與比較
1
.橋接模式與裝飾模式
這兩個(gè)模式在一定程度上都是為了減少子類(lèi)的數(shù)目,避免出現(xiàn)復(fù)雜的繼承關(guān)系。但是它們解決的方法卻各有不同,裝飾模式把子類(lèi)中比基類(lèi)中多出來(lái)的部分放到單獨(dú)的類(lèi)里面,以適應(yīng)新功能增加的需要,當(dāng)我們把描述新功能的類(lèi)封裝到基類(lèi)的對(duì)象里面時(shí),就得到了所需要的子類(lèi)對(duì)象,這些描述新功能的類(lèi)通過(guò)組合可以實(shí)現(xiàn)很多的功能組合,裝飾模式的簡(jiǎn)略圖如下:
橋接模式則把原來(lái)的基類(lèi)的實(shí)現(xiàn)化細(xì)節(jié)抽象出來(lái),在構(gòu)造到一個(gè)實(shí)現(xiàn)化的結(jié)構(gòu)中,然后再把原來(lái)的基類(lèi)改造成一個(gè)抽象化的等級(jí)結(jié)構(gòu),這樣就可以實(shí)現(xiàn)系統(tǒng)在多個(gè)維度上的獨(dú)立變化,橋接模式的簡(jiǎn)略圖如下:
圖2 橋接模式簡(jiǎn)略圖
2
.外觀(guān)模式和代理模式
外觀(guān)模式和代理模式解決問(wèn)題的側(cè)重點(diǎn)不同,但是它們解決問(wèn)題的手法卻是一樣的,即都是引入了間接層的手法,這也是我們軟件系統(tǒng)中經(jīng)常用的一種手法。外觀(guān)模式雖然側(cè)重于簡(jiǎn)化接口,但是在某些情況下,外觀(guān)模式也可以兼任代理模式的責(zé)任,例如外觀(guān)對(duì)象有可能是另一個(gè)位于另一個(gè)地址空間對(duì)象的遠(yuǎn)程代理,這時(shí)候我們可以叫做外觀(guān)代理模式,或者代理外觀(guān)模式。它們的類(lèi)簡(jiǎn)略圖如下:

圖3 代理模式簡(jiǎn)略圖
3
.適配器模式
適配器模式重在轉(zhuǎn)換接口,它能夠使原本不能在一起工作的兩個(gè)類(lèi)一起工作,所以經(jīng)常用在類(lèi)庫(kù)復(fù)用,代碼遷移等方面,有一種亡羊補(bǔ)牢的味道。類(lèi)適配器和對(duì)象適配器可以根據(jù)具體實(shí)際情況來(lái)選用,但一般情況建議使用對(duì)象適配器模式,如下圖所示,左邊是類(lèi)適配器模式,右邊是對(duì)象適配器模式:
圖5 適配器模式簡(jiǎn)略圖
對(duì)變化的封裝
如何應(yīng)對(duì)變化,是軟件開(kāi)發(fā)的一個(gè)永恒的主題,也許我們不能夠杜絕變化的發(fā)生,但至少我們可以通過(guò)一些手段讓變化降到最低。“找到系統(tǒng)可變的因素,將之封裝起來(lái)”,通常就叫做對(duì)變化的封裝。關(guān)于這個(gè)問(wèn)題的解釋在《
Java
與模式》中講的很清晰,抽象化與實(shí)現(xiàn)化的簡(jiǎn)單實(shí)現(xiàn),也就是“開(kāi)
-
閉”原則在類(lèi)層次上的最簡(jiǎn)單實(shí)現(xiàn),如下圖所示:
在這個(gè)繼承結(jié)構(gòu)中,第一層是抽象化,它封裝了抽象的業(yè)務(wù)邏輯,這是系統(tǒng)中不變的部分;第二層是實(shí)現(xiàn)化,它是具體的業(yè)務(wù)邏輯的實(shí)現(xiàn),封裝了系統(tǒng)中變化的部分,這個(gè)實(shí)現(xiàn)允許實(shí)現(xiàn)化角色多態(tài)性的變化:
也就是說(shuō),客戶(hù)端依賴(lài)的是業(yè)務(wù)邏輯的抽象化類(lèi)型的對(duì)象,而與抽象化的具體實(shí)現(xiàn)無(wú)關(guān),不在乎它到底是“實(shí)現(xiàn)化”,“實(shí)現(xiàn)化
2
”還是“實(shí)現(xiàn)化
3
”,如下圖所示:
每一種繼承關(guān)系都封裝了一個(gè)變化因素,而一個(gè)繼承關(guān)系不應(yīng)當(dāng)處理兩個(gè)變化因素,換言之,這種簡(jiǎn)單繼承關(guān)系不能處理抽象化與實(shí)現(xiàn)化都變化的情況,如下圖所示:
上圖中的兩個(gè)變化因素應(yīng)當(dāng)是獨(dú)立的,可以在不影響另一者的情況下獨(dú)立的變化,如下面這兩個(gè)等級(jí)結(jié)構(gòu)分別封裝了自己的變化因素,由于每一個(gè)變化因素都是可以通過(guò)靜態(tài)關(guān)系表達(dá)的,因此分別使用繼承關(guān)系實(shí)現(xiàn),如下圖:
在抽象化和實(shí)現(xiàn)化之間的聯(lián)系怎么辦呢?好的設(shè)計(jì)只有一個(gè),不好的設(shè)計(jì)卻有很多中,下面這種設(shè)計(jì)就是繼續(xù)使用繼承進(jìn)行靜態(tài)關(guān)系設(shè)計(jì)的類(lèi)圖:
這樣的設(shè)計(jì)其實(shí)存在著很多的問(wèn)題,首先出現(xiàn)的是多重的繼承關(guān)系,隨著具體實(shí)現(xiàn)化的增多,子類(lèi)的繼承關(guān)系會(huì)變得異常復(fù)雜;其次如果出現(xiàn)新的抽象化修正或者新的具體實(shí)現(xiàn)角色,就只好重新修改現(xiàn)有系統(tǒng)中的靜態(tài)關(guān)系,以適應(yīng)新的角色,這就違背了開(kāi)放
-
封閉原則。正確是設(shè)計(jì)應(yīng)該是使用兩個(gè)獨(dú)立的等級(jí)結(jié)構(gòu)封裝兩個(gè)獨(dú)立的變化因素,并在它們之間使用聚合關(guān)系,以達(dá)到功能復(fù)用的目的,這就回到了我們的橋接模式上,如下圖所示:
從另一個(gè)角度講,一個(gè)好的設(shè)計(jì)通常沒(méi)有多于兩層的繼承等級(jí)結(jié)構(gòu),或者說(shuō),如果出現(xiàn)兩個(gè)以上的變化因素,就需要找出哪一個(gè)因素是靜態(tài)的,可以使用靜態(tài)關(guān)系,哪一個(gè)是動(dòng)態(tài)的,必須使用聚合關(guān)系。
更多的設(shè)計(jì)模式文章可以訪(fǎng)問(wèn)《
.NET
設(shè)計(jì)模式系列文章
》
參考資料
Erich Gamma
等,《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》,機(jī)械工業(yè)出版社
Robert C.Martin
,《敏捷軟件開(kāi)發(fā):原則、模式與實(shí)踐》,清華大學(xué)出版社
閻宏,《
Java
與模式》,電子工業(yè)出版社
Alan Shalloway James R. Trott
,《
Design Patterns Explained
》,中國(guó)電力出版社
(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第14章 結(jié)構(gòu)型模式專(zhuān)題總結(jié)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
