天天看點

設計模式-結構模式之小結

更多請移步: 我的部落格

目的

結構設計模式使的我們簡單快速的建立類的層級及不同類之間的關系,明确不同層級間的責任和邊界,讓各個子產品、系統間互相獨立并很好的協作。

概覽

Adapter模式

擴充卡的目的是使不相容接口間的可正常進行協作,它允許我們新增接口。主要用來解決下面兩個問題:

  • 接口間輸入輸出不比對的問題,擴充卡在無法互相直接使用的接口間加入中間轉換層,對資料格式進行轉換,使接口間可以順利協作。
  • 當你需要複用幾個已經存在的類,但是它們缺少一些常用的功能。并且你無法在父類中添加這些功能,因為他是閉源或者被其他代碼使用的。可以把這些缺少的功能放到建立的擴充卡中。

比如像OutputStreamWriter,它在構造方法中接收一個OutputStream作為内部變量。OutputStream并沒有提供對String或者char類型的支援,于是OutputStreamWriter就出現了,OutputStreamWriter的基類定義了該接口要實作的功能,然後适配傳入的字元串,但是最終還是把輸出工作交給了OutputStream。

Adapter反對完全重新定義一個接口,原文沒有對完全重新定義接口作出解釋,但是它改變了原有接口,不過也不必太過于糾結于此。隻要我們根據設計模式提供的思維方式把問題很好的解決就好。

Facade模式

門面讓你為一個複雜的系統,類庫或者架構提供一個簡單的接口。可用在以下場景:

  • 需要一個簡單但是功能有限的複雜子系統接口時
  • 把一個子系統建構成層級結構

上面兩個場景在實際場景中很多,比如我們要使用第三方的類庫,但是它并沒有提供我們想要的接口,于是我們自己建立一個類來對它進行包裝,并在這個類中管理三方庫中一些對象的生命周期。

Decorator模式

裝飾器讓你在封裝包涵對象原有行為的基礎上增加新的行為。可用在以下場景:

  • 動态賦予某個對象行為并且不需要修改這個對象的代碼
  • 不可能或者不合适通過繼承來擴充對象的行為

裝飾器是對已有接口的增強,它沒有改變原有的接口,對使用者完全透明。比如我們會用Collections的synchronizedMap(Map

Proxy模式

代理模式為另外一個對象提供一個替身或者占位符來控制對它的通路。作用如下:

  • 懶初始化(虛拟代理)。當你有一個需要從檔案系統,網絡或者資料庫加載資料的重量級對象時。
  • 通路控制(保護代理)。當一個程式有不同類型的使用者并且你想阻止未授權使用者對保護對象的通路。
  • 本地執行一個遠端服務(遠端代理)。當一個真實服務對象在遠端伺服器上時。
  • 緩存對象(智能引用)。當你需要混存用戶端的請求并且管理它們的生命周期時(當結果比較重時)時。
  • 請求日志(日志代理)。當你需要保留一個服務對象的請求曆史。

代理還分為靜态和動态兩種,動态代理常用在架構層面。上面列出的幾個适用場景在Dubbo中有很好的展現,Dubbo代理了遠端的服務,并對其做了緩存和通路控制等相關名額資料。了解Proxy模式去看下Dubbo源碼是個不錯的選擇。

還是要從主要目的或者說意圖上區分模式,Proxy并不像Decorator那樣對接口做增強,也不像Adapter定義新的接口,但并不是Proxy做不了這些事情,它可以很輕松的對接口做增強,但那不是他的主要目的。PS:Proxy往往需要管理被代理對象的生命周期。

Composite模式

Composite模式讓我們可以像樹一樣組合對象,并且允許用戶端像操作單個對象一樣和這些結構協作。使用該模式前一定要正确梳理清楚現有實體間抽象關系。

當有以下場景時,考量使用該模式:

  • 需要實作一個像樹一樣有着簡單元素和容器的結構。
  • 用戶端要統一處理簡單和複雜的元素時。

之前接觸一個店鋪裝修系統,使用者使用定義好的基本元件組合出不同的網頁效果。像系統中的輸入框、圖檔、按鈕等是基本的元件(像樹的葉子),使用者可以使用基本元件組成更複雜的元件放到自定義元件中(像一個樹枝),自定義元件和基本元件遵循相同的接口,有着相同的屬性和操作。這樣,渲染引擎在渲染在将一個畫面渲染的時候隻需要關注目前畫面用了那些元件,不必關心元件式什麼類型的,隻需要通過接口設定/擷取自己需要的屬性值即可。

組合模式和裝飾模式很像,都依賴遞歸組合,但不同的是,裝飾器用來增強接口而組合模式隻是對接口結果做了合并。不必糾結于如此一點差别。就像黑貓VS白貓,捉到老鼠就是好貓。

Bridge模式

橋接模式分離一個巨大的類或者将一組關系相近的類分離成為兩個獨立的層次結構,抽象和實作,讓各自可以獨立開發。

這個模式提示我們,接口和實作必須分開。不過,現在企業級項目好像沒有不這樣做的。使用場景如下:

  • 有一個包含一些功能變種的大類(工作在幾個不同的資料庫服務上)
  • 需要在正交(獨立)的次元擴充一個類(例子詳見Bridge模式)
  • 需要在運作時改變實作(一個接口多種實作,比如:臨時切換系統的支付通道)

Flyweight模式

享元來自于拳擊界,表示輕量級選手(選手小于111磅)。這個舶來詞形象表明這個模式的意圖。通過在多個對象見共享對象狀态的通用部分而不是讓各個對象獨自持有的方式來節約記憶體。我們在系統中常會定義一些常量供不通的對象使用,這也展現了享元模式的思想。在Java的核心類庫中,像Integer、Boolean、Long和BigDecimal等都緩存了常用的(最大/小/0等)數值。

小結

翻譯的文章對模式的解釋比較淺顯簡單,可以讓我們對模式有一個初步的認知,想要更深入了解和體會設計模式一方面離不開平時做項目時對業務和代碼關于模式思考,嘗試在編碼時采用一些合适的模式,将理論運用到實踐中,直覺上體驗模式帶來的好處和問題;另一方面還是要深入讀下《設計模式》這本書,來加深對模式的了解。個人認為模式的具體實作結構不必拘泥文中說的某種實作形式,它更重要的是要解決什麼問題,以及我們可能會碰到什麼問題,和優雅解決或者避免這些問題的方法。具體怎樣去應用一個模式在單一介紹模式的文章中都有給出。

本次小結的這幾種設計模式屬設計模式中的結構部分,它告訴我們怎樣比較合理的抽象資料結構間的層次和關系,也講明了采用給出解決方法的會帶來的一些問題。當然,一些場景的處理可能會有幾種模式都可以适用,這時候就需要根據自己的主要意圖、複雜性等方面來考量了,畢竟,複雜的代碼讓人讨厭。

TODO 目前對結構模式還是入門了解,會在看完《設計模式》中對結構模式的講解後再來更新自己的這篇博文(2017年11月3日)。

繼續閱讀