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

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

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