設計模式——結構型模式

1.代理模式※

(1)代理模式的定義

       代理模式給某一個對象提供一個代理對象,並由代理對象控制對原對象的引用。通俗的來講代理模式就是我們生活中常見的中介。

       Proxy模式在訪問對象時引入了一定程度的間接性。根據代理的類型,附加的間接性有很多種用途:

遠程代理(Remote Proxy)可以隱藏一個對象存在於不同地址空間的事實。

虛代理(Virtual Proxy)可以進行最優化,例如根據要求創建對象。

保護代理(Protection Proxies)和智能引用(Smart Reference)都允許在訪問一個對象時有一些附加的內務處理。

 

(2)爲什麼要用代理模式

       中介隔離作用:在某些情況下,一個客戶類不想或者不能直接引用一個委託對象,而代理類對象可以在客戶類和委託對象之間起到中介的作用,其特徵是代理類和委託類實現相同的接口。

       開閉原則,增加功能:代理類除了是客戶類和委託類的中介之外,我們還可以通過給代理類增加額外的功能來擴展委託類的功能,這樣做我們只需要修改代理類而不需要再修改委託類,符合代碼設計的開閉原則。代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後對返回結果的處理等。代理類本身並不真正實現服務,而是同過調用委託類的相關方法,來提供特定的服務。真正的業務功能還是由委託類來實現,但是可以在業務功能執行的前後加入一些公共的服務。例如我們想給項目加入緩存、日誌這些功能,我們就可以使用代理類來完成,而沒必要打開已經封裝好的委託類。

 

3)優缺點

A.優點

       代理模式能夠協調調用者和被調用者嗎,在一定程度上降低了系統的耦合度。

       遠程代理是的客戶端可以訪問在遠程機器上的對象,遠程機器可能具有更好的計算性能與處理速度,可以快速響應並處理客戶端請求。

       虛擬代理通過使用一個小對象來代表一個大對象,可以減少系統資源的消耗,對系統進行優化並提高運行速度。

      保護代理可以控制對真實對象的使用權限。

B. 缺點

       由於在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢。

       實現代理模式需要額外的工作,有些代理祕書的實現比較複雜。

 

(4) 適用性

下面是一些可以使用Proxy模式常見的情況:

遠程代理(Remote Proxy) 爲一個對象在不同的地址空間提供局部代表。

虛代理(Virual Proxy) 根據需要創建開銷很大的對象。

保護代理(Protection Proxy) 控制對原始對象的訪問。保護代理用於對象應該有不同的訪問權限的時候。

智能指引(Smart Reference) 取代了簡單的指針,它在訪問對象時執行一些附加操作。典型用途包括:

對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放它。

當第一次引用一個持久對象時,將它裝入內存。

在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其他對象不能改變它。

 

(5)與適配器模式的區別

       適配器模式是由於原接口與目標接口不兼容而產生的。代理模式則擁有與被代理者相同的接口,但是其具有自己獨有的職責,將使用與被代理者的實現隔離開來。

(6)動態代理

       Java使用JDK實現動態代理類技術核心爲Proxy類和一個InvocationHandler 接口。

 

2.裝飾模式※

(1)概念

       時常會遇到這樣一種情況,我已經設計好了一個接口,並且也有幾個實現類,但是這時我發現我設計的時候疏忽了,忘記了一些功能,或者後來需求變動要求加入一些功能,最簡單的做法就是修改接口,添加函數,然後繼承類中都相應的添加實現,這樣做倒也沒什麼問題,但是如果這種變化來個好幾次或者繼承類非常多,那工作量可就大了。

       所以大神們想出了裝飾模式(Decorator),動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更爲靈活。

                            

 

用法:

int main()  

{    

Component* pComponent = new ConcreteComponent();      

ConcreteDecorator* pConDecorator = new ConcreteDecorator();       pConDecorator->setComponent(pComponent);    

  pConDecorator->operation();    

pConDecorator->addBehavior();    

 return 0;

}

 

2優缺點

A.優點

       比靜態繼承更靈活 與對象的靜態繼承(多重繼承)相比,Decorator模式提供了更加靈活的向對象添加職責的方式。可以用添加和分離的方法,用裝飾在運行時刻增加和刪除職責。相比之下,繼承機制要求爲每個添加的職責創建一個新的子類。這會產生許多新的類,並且會增加系統的複雜度。此外,爲一個特定的Component類提供多個不同的Decorator類,這就使得你可以對一些職責進行混合和匹配。

       避免在層次結構高層的類有太多的特徵 Decorator模式提供了一種“即用即付”的方法來添加職責。它並不試圖在一個複雜的可定製的類中支持所有可預見的特徵,相反,你可以定義一個簡單的類,並用Decorator類給它逐漸地添加功能。可以從簡單的部件組合出複雜的功能。

B.缺點

       Decorator與它的Component不一樣 Decorator是一個透明的包裝。如果我們從對象標識的觀點出發,一個被裝飾了的組件與這個組件是有差別的,因此,使用裝飾時不應該依賴對象標識。

       有許多小對象 採用Decorator模式進行系統設計往往會產生許多看上去類似的小對象。這些對象僅僅在他們相互連接的方式上有所不同,而不是它們的類或是它們的屬性值有所不同。儘管對於那些瞭解這些系統的人來說,很容易對它們進行定製,但是很難學習這些系統,排錯也很困難。

 

3適用性

  以下情況使用Decorator模式:

       在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。 

       當不能採用生成子類的方法進行擴充時。一種情況是,可以有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因爲類定義被隱藏,或類定義不能用於生成子類。

 

3.適配器模式

       將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由於接口不兼容而不能在一起工作的那些類可以一起工作。——《設計模式:可複用面向對象軟件的基礎》

1類適配器模式(class adapter pattern)

 

2對象適配器模式(object adapter pattern)

 

3)缺省適配器模式(default adapter pattern),也叫默認適配器模式、接口適配器模式

 

(4)缺點過多地使用適配器,增加系統理解難度。

 

(5)和代理模式的區別

       適配器模式是由於原接口與目標接口不兼容而產生的。代理模式則擁有與被代理者相同的接口,但是其具有自己獨有的職責,將使用與被代理者的實現隔離開來。

 

4.外觀模式

       外觀模式通過爲多個複雜的子系統提供一個一致的接口,而使這些子系統更加容易被訪問的模式。該模式對外有一個統一接口,外部應用程序不用關心內部子系統的具體的細節,這樣會大大降低應用程序的複雜度,提高了程序的可維護性。

 

 

5.橋接模式

(1)模式來源

       設想如果要繪製矩形、圓形、橢圓、正方形,我們至少需要4個形狀類,但是如果繪製的圖形需要具有不同的顏色,如紅色、綠色、藍色等,此時至少有如下兩種設計方案:

        • 第一種設計方案是爲每一種形狀都提供一套各種顏色的版本。

 

        • 第二種設計方案是根據實際需要對形狀和顏色進行組合。

 

       對於有兩個變化維度(即兩個變化的原因)的系統,採用方案二來進行設計系統中類的個數更少,且系統擴展更爲方便。設計方案二即是橋接模式的應用。

 

2模式結構

 

實例a:

 

這就將pen和color分離開來,各自發展。

實例b,跨平臺播放器:

 

 

6.組合模式

(1)定義:將對象組合成樹形結構以表示“部分-整體”的層次結構,使客戶端對單個對象和組合對象保持一致的方式處理。所以,合成模式必須在合適的地方提供子對象的管理方法,諸如:add()、remove()、以及getChild()等。透明式的合成模式要求所有的具體構件類,不論樹枝構件還是樹葉構件,均符合一個固定接口,如下。

 

(2)示例:文件系統就是典型的組合模式,如下圖是window系統D盤符下的部分目錄組織結構,紅橙色的是目錄,淺綠色的是文件,這裏目錄和文件是可以看成是同一種對象對待。

 

 

7.享元模式

(1)定義:運用共享技術有效地支持大量細粒度的對象。

 

(2)示例

       String常量池、數據庫連接池、緩衝池等等都是享元模式的應用,所以說享元模式是池技術的重要實現方式。

  比如我們每次創建字符串對象時,都需要創建一個新的字符串對象的話,內存開銷會很大,所以如果第一次創建了字符串對象“adam“,下次再創建相同的字符串”adam“時,只是把它的引用指向”adam“,這樣就實現了”adam“字符串再內存中的共享。

方法就是用唯一標識碼判斷,如果在內存中有,則返回這個唯一標識碼所標識的對象,用HashMap/HashTable存儲。

 

參考:

https://www.cnblogs.com/daniels/p/8242592.html

https://blog.csdn.net/huangjh2017/article/details/78595072

https://www.cnblogs.com/cxjchen/p/3161686.html

https://blog.csdn.net/huangjh2017/article/details/78524418

https://www.cnblogs.com/mingmingcome/p/9810731.html

https://www.cnblogs.com/alsf/p/8506912.html

https://www.jianshu.com/p/6c721472be83

https://blog.csdn.net/huangjh2017/article/details/78472975

https://blog.csdn.net/u014727260/article/details/82722473

https://www.cnblogs.com/adamjwh/p/9070107.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章