23種設計模式(超級簡潔)


-By Jason McDonald

關於設計模式  

這個設計模式參考提供四人幫23種模式的快速參考,像原書《設計模式-可復用面向對象基礎》中所陳述的,每個模式包括,類圖,解釋,使用說明和實際例子。

 

創建模式:用來構建對象以便能從實現系統解耦。

結構模式:用不同的對象組成大規模的對象結構。

行為模式:用來在對象中管理算法,關系,和責任。

 

對象層面:處理對象之間的關系,決定於運行期。

類層面:處理類的關系,決定於在編譯期。

 

 

Chain of Responsibility責任鏈    對象行為 

 

image

目的:

通過把多個接受請求的對象鏈接起來,給多個對象去執行請求的機會。

使用:

  • 允許多個對象處理一個請求,處理者不必是特定的對象。
  • 存在一組對象可以去處理請求,動態決定到底是哪一個處理者。
  • 可以接受潛在的情形是請求最終沒有被任何Handler處理。

例子:

某些語言的異常處理使用此模式,當一個異常被方法拋出時,運行時檢查那個方法有沒有機制去處理異常。或者它應該沿調用堆棧向上傳遞。向上傳遞的過程持續,直到處理這個異常的代碼找到,或者沒有更外層的父類對象來處理異常。

 

Command命令   對象行為  

 

image

 

 

目的:

封裝一個請求,允許它作為一個對象來對待, 這樣允許請求被作為隊列(Queuing)或回調(Callbacks)中的傳統對象來處理

使用:

  • 你需要回調(Callbacks)功能
  • 多個請求需要在不同時間或不同順序被處理
  • 請求日志需要記錄
  • 發起者需要和處理命令的對象(Receiver)解耦。

例子:

工作隊列廣泛應用於異步處理的算法。通過命令模式,要執行的功能可以發給一個工作隊列,而工作隊列無需知道發起的請求的實際實現,排隊的命令對象用自己的算法實現了隊列期望的靜態接口。

 

 

Interpreter解釋器    類型行為   

image

目的:

定義一個語法表示,和一種理解處理語法的機制

 

使用:

語法可以被解釋成一顆大的語法樹。

語法簡單。

效率不重要。

語法和底層的表達式解耦。

 

例子:

文字類的冒險游戲,1980年代相當流行,提供了一個很好的例子。 很多都有簡單的命令,比如“向下走”允許對游戲的遍歷。這些命令可以嵌套,如此得以改變他們的意思。例如,“go in”將導致和”go up”不同的結果。基於命令和修飾符(終結和非終結表達式)創建出的命令等級系統,應用可以很容易映射很多不同命令到一個行為樹。

 

 

Mediator調停者    對象行為   

image

目的:

通過封裝不同的對象集之間的交互和通訊實現松耦合, 允許每個對象集的行為相對於其他對象獨立的演化。

 

使用:

不同對象集之間通信事先被定義,並且復雜。

通信和控制的節點之間存在太多的關系。

 

例子:

郵件列表軟件記錄登記到郵件列表的用戶,並提供一個入口,通過這個入口,任何人都可以給整個郵件列表發郵件。 沒有調停者模式實現的話,那個人必須隨時關注誰訂閱了列表,而誰又沒有訂閱。通過實現調停者模式,系統可以從任何入口接受郵件,然后決定哪些接收者需要傳送,而不需要發送者擔心真正的接收名單。

 

 

Iterator迭代子    對象行為   

image

目的:

允許得到一個聚集的元素,而不使用聚集本身的底層實現。

 

使用:

只需要得到聚集的元素,而不用知道整個聚集的內部表現。

需要對所有元素的多個或並行遍歷。

需要對不同聚集的一個統一接口。

不同迭代子的實現細節有細微差異存在。

 

例子:

Java對迭代子模式的實現允許用戶可以遍歷不同類型的數據集合,而不用擔心集合的底層實現。由於客戶端只和迭代子接口打交道,各種集合可以留出余地定義一個適合他們的接口。有些允許存取所有集合的數據,有些禁止了某些功能,比如移除一些元素。

 

Memento備忘錄    對象行為   

image

目的:

允許存儲和外化一個對象的內部狀態以便以后可以恢復,而這一切並不破壞封裝。

 

使用:

對象的內部狀態必須存儲以備以后某個時間恢復。

一個接口的內部狀態不通過暴露實現就不能被使用。

封裝邊界必須被保留。

 

例子:

Undo功能可以通過備忘錄模式得到很好實現。 在狀態變化之前,通過序列化和反序列化一個對象的狀態可以保留它的一個快照,如果用戶需要undo操作的話,可以用這個快照恢復。

 

 

Observer觀察者    對象行為   

image

目的:

當系統中的主題對象狀態發生變化時,讓一個或多個觀察者對象得到通知。

 

使用:

一個或多個對象的狀態發生變化應該激發其他對象的行為。

需要廣播(消息)的能力。

一個須知是,對象無視得到通知的代價。

 

例子:

這個模式幾乎可以在任何界面環境中見到,當應用中出現按鈕,文字,和其他變量,應用一般登記為這些控件的觀察者(Listener),當一個用戶激發一個事件,比如點擊一個按鈕, 控件遍歷所有它登記的觀察者(Observers)並對每個觀察者一一發送通知。

 

 

Strategy策略    對象行為   

image

目的:

定義一個系列的封裝好的算法,可以互換以用來實現特定行為。

 

使用:

類之間的唯一區別是他們的行為。

需要一個算法的不同版本或演化。

算法存取或使用的數據不應該被暴露給調用方。

一個類的行為應該在運行時決定。

條件語句復雜而且難以維護,需要重構

 

例子:

當數據被導入到新系統的時候,不同的驗證算法需要運行於數據之上。通過配置,導入和使用策略,決定哪些驗證需要被運行的條件邏輯可以移除掉,(數據)導入可以和真實驗證代碼解耦。 這會允許我們導入數據時動態調用一個或多個策略。

 

State狀態    對象行為   

image

目的:

對象的情景綁定到它的行為上,允許對象根據內部狀態表現不同行為。

 

使用:

對象的行為受它的狀態影響。

把對象行為綁定到狀態的條件復雜。

狀態間需要顯式轉換。

 

例子:

一個郵件對象可以有不同狀態,這些狀態會影響對象的功能, 如果狀態是“待發”,那么調用send()將會發出郵件,而調用recallMessage()會拋出錯誤或什么也不干,然而,如果狀態時“已發出”狀態,那么調用send()會拋出錯誤或什么也不干,而調用recallMessage()會嘗試發送提醒通知給接受者。為避免方法中出現條件轉移語句, 會使用多個狀態對象處理相對應於特定狀態的行為實現。郵件對象里的調用方法會委派給適當的狀態對像來處理。

 

 

Template Method模板方法    類行為   

image

目的:

標識識別一個算法的框架,允許實現類頂一個真正的行為。

 

使用:

需要算法的一個抽象的是實現。

所有子類的共同行為需要放置到共同類中。

父類應該統一調用所有子類中的行為。

大部分或所有子類需要實現一個共同的行為。

 

例子:

一個父類,InstantMessage,需要所有的方法去處理發送消息,但是要發送的序列化數據可能根據不同實現而不同,一個視頻消息和一個文字消息需要不同的算法以使數據正確序列化。InstantMessage的子類可以產生他們各自的序列化實現方法。允許父類可以和他們一起作用,而無需知道各自的實現細節。

 

Visitor訪問者    對象行為   

image

這個圖漏了ConcreteVisitor到Visitor的繼承關系,讀者心中有數。

 

目的:

允許運行時對一組對象進行一種或幾種操作,而把對象結構和操作解耦。

 

使用:

一個對象結構須有多個不相關的操作作用其上。

一個對象結構不能改變,當時作用其上的操作可以變。

操作必須要作用在對象結構的具體類上。

可以接受對象結構暴露出來的內部狀態和操作。

操作需要能夠作用在繼承統一的接口集合的對象結構之上。

 

例子:

對不同地區的一組發票計算稅收需要很多不同的計算邏輯。實現訪問者模式允許計算稅收邏輯可以和發票詳細項目解耦(我的理解是發票有很多不同的部分,每個部分需要不同的計稅方式)。訪問發票項目等級結構的計算邏輯可以和地區的合適稅率解耦。改變地區就是簡單改變一個不同的訪問者具體類。

 

 

Bridge橋梁    對象結構   

image_thumb[1]

目的:

定義一個抽象化角色對象結構 和一個獨立的實現化角色對象結構,抽象化角色的對象通過委派到實現化角色的對象來實現自己的功能,同時又能靈活的改變實現化角色對象的引用,因此達到解耦。

 

使用:

抽象化角色和實現化角色不應該在編譯期綁定。

 

例子:

JVM, Java虛擬機有他自己的本地方法,抽象了視窗,系統日志,和字節碼執行的使用,這些方法的具體實現委派到JVM運行的操作系統之上。當一個應用指示JVM去渲染窗口,他委派這個渲染的調用去JVM的具體實現,JVM知道怎么樣和操作系統通信,以便渲染這個窗口。

 

Adapter適配器    類和對象結構   

image

這個圖中的Adapter接口是源角色,所以又叫Target

目的:

通過這個具體適配器對象,使原本接口不匹配而無法一起工作的類能夠一起工作。

 

使用:

一個要使用的類不滿足接口需要。

復雜的條件把對象的行為綁定到他的狀態。

狀態需要顯式轉換。

 

例子:

一個賬單應用需要人事應用的接口,以便交換雇員數據。但是他們都有自己對雇員數據接口的實現, 另一個要命的地方他們的社會安全保障號碼使用不同的格式,通過在兩個應用之間創建一個適配器類, 允許他們使用本地的對象來通信,也可以在這個過程中轉換SSN格式。

 

 

 

 

Composite組合    對象結構   

image

目的:

合成模式使客戶端將單純元素和復合元素同等看待,方便創建對象的樹結構。

 

使用:

需要對象的等級結構時,

單純對象和復合對象可以統一對待。

 

例子:

有時候購物車的顯示內容是一個單獨項目或多個項目的集合。將項目(item)實現為一個Composite接口的子類,我們就可以把集合項目和單純項目統一對待,允許我們遍歷對象樹,調用每個項目的方法。通過調用一個節點的getCost方法,我們可以得到那個項目的金額,和所有子項目的金額。無論他們是單純項目還是一組項目都可以統一被看待。

 

 

 

 

Decorator裝飾    對象結構   

image

 

目的:

允許動態包裝對象以便修改它們現有的責任和行為。

 

使用:

對象責任和行為應該可以被動態地修改。

具體實現應該和責任和行為解耦。

用繼承的方式去修改變得不實際和不可能。

特定功能不應駐留在對象層次的上層。

一大堆小對象包裹在具體實現周圍是可以接受的。

 

例子:

很多公司利用裝飾模式搭建郵件系統,當一個郵件從公司內部發送到外部郵件地址時,郵件服務器自動在原來的內容加上版權和機密信息,如果是發往內部地址,就不添加。這種裝飾允許郵件本身不發生改變,添加額外信息的判斷在運行時被執行。

 

 

Flyweight享元    對象結構   

image

目的:

方便重用某些細粒度的對象,使對大量對象的使用更有效率。

 

使用:

很多相同的對象被使用而且存儲代價比較高。

每個對象的主要狀態可以外部存放。

有些共享對象可以代替很多不共享的對象。

每個對象的標識不重要。

 

例子:

系統允許用戶定義他們自己的應用流程和布局經常需要跟蹤記錄很多數量的變量,頁面和其他項目,而這些東西幾乎沒有差別,通過把這些東西做成享元對象,所有對象的實例可以共享內部狀態,而把外部狀態分開存放。內部狀態將存儲共享屬性,比如一個對話框的視覺效果,可以裝多少長度的數據,暴露出什么樣的事件,外部狀態會存儲不共享的屬性,比如項目的位置,怎樣對用戶的點擊做出反應,怎么樣處理事件。

 

 

Facade門面    對象結構   

image

 

目的:

為一個子系統里面的一組接口提供一個單獨的接口

 

使用:

需要一個簡單的接口提供對一個復雜系統的訪問

在系統實現和客戶之間存在過多的依賴

系統和子系統需要被分層

 

例子:

通過Web服務暴露一組功能,客戶代碼只需要關心通過web服務暴露給他們的一個簡單接口,而不是隱藏在web服務層后面存在的可能有的復雜關系。用新數據通過一個單獨的web服務調用去更新系統可能涉及和幾個數據庫和系統的通信,然而這一切細節門面模式隱藏起來。

 

 

Proxy代理    對象結構   

image

 

目的:

允許對象層的存取控制,像一個Pass through entity或placeholder object。

 

使用:

被代表的對象存在於系統的外部。

對象可以在需要時創建。

對真正要訪問的對象提供存儲控制。

當一個對象被存取時需要增加功能。

 

例子:

賬本應用提供一個方式顧客可以用他們的銀行對賬單和銀行記錄進行對賬。 使很多過程自動化,和第三方通信的真正的操作十分耗費資源,應該被限制執行次數。通過使用代理來表示通信對象,我們可以限制通信時間和間隔,更進一步的是,我們可以把復雜的通信對象的初始化操作隱藏在代理類里面,是調用代碼和是實現細節解耦。

 

 

Abstract Factory抽象工廠    對象創建   

image

 

目的:

提供一個接口,為了創建某些特定對象,把創建調用委派給某些具體創建類。

 

使用:

對象的創建應獨立於是使用它們的系統。

系統應該能夠使用多個對象族。

一個族的對象應該被集中使用。

程序庫發布的時候不會暴露出其實現細節。

具體類應該和客戶端解耦。

 

例子:

郵件編輯器應該允許操作多種格式,包括純文字,富格式文字,和HTML。 根據被使用的格式,不同的對象需要被創建。如果郵件是純文字,那么主體對象表示的就是純文字和一個附件對象只是把附件簡單編碼成Base64。如果郵件是HTML,那么主體對象表示HTML 編碼文字,附件對象允許inline表示和標准附件。通過利用抽象工廠來創建,我們可以保證合適的對象族根據郵件的風格來創建。

 

 

 

Factory Method工廠方法    對象創建   

image

 

目的:

暴露一個方法來創建對象,允許子類來控制真正的創建過程。

 

使用:

一個類不知道他要創建的是什么對象。

子類可以指定需要創建的對象。

父類希望將創建的操作放在它的子類。

 

例子:

很多應用有一種user 和 group結構來做登錄,當應用需要創建一個user,它將通常把創建的過程委派給多個工廠方法子類實現。父類User對象將處理每種User的大部分操作,但是子類將定義工廠方法處理不同種類的User創建的差別。系統可能有AdminUser和StandardUser對象,每一個繼承了User,AdminUser對象執行某些任務保證使用權,而StandardUser卻要限制使用權。

 

 

Builder建造者    對象創建   

image

 

目的:

允許根據一些容易替換的算法動態創建對象。

 

使用:

對象創建算法應該和系統解耦。

需要創建算法的多種表示。

添加新的創建行為而不改變主要代碼。

需要創建過程的運行時控制。

 

例子:

一個文件傳輸應用應該使用很多不同的協議來發送文件,真正的傳輸對象要根據選擇的傳輸協議。通過使用一個Builder,我們可以決定使用正確的Builder來實例化正確的對象。 如果設置里是FTP那么FTP Builder將被使用。

 

 

 

 

Prototype原型    對象創建   

image

 

目的:

根據一個已經存在的對象作為模板通過克隆來創建對象。

 

使用:

組合,創建和對象的表示應該和系統解耦。

要創建的類在運行時才決定。

一個對象內部存在有限數目的狀態。

對象或需要的對象結構需要一致或非常接近其他已經存在的對象和對象結構。

一開始對每個對象的創建是一個很耗費的操作。

 

例子:

價格處理引擎常常需要尋找很多不同的配置參數,是初始化這個引擎來變得相對昂貴,當有幾個這樣的引擎實例需要初始化,使用多線程來導入數據。很多引擎的初始化耗費就會很高。通過使用原型模式,我們可以保證只有一個引擎的拷貝需要初始化,然后克隆這個實例來復制它。附加的好處是克隆可以流程化。

 

 

 

Singleton單例    對象創建

image

 

目的:

保證系統里只有一個類的實例。

 

使用:

只需要類的一個實例。

必須控制使用一個單獨對象。

 

例子:

很多語言提供系統或環境對象,允許語言和本地操作系統交互。因為物理上在一個操作系統上運行的應用,只需要一個系統對象。單例模式被語言運行時來保證只有一個系統對象的拷貝被創建,只有合適的進程才可以訪問它。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM