設計模式:(五)相似模式比較
一、工廠方法模式VS建造者模式
工廠方法模式注重的是整體物件的建立方法,而建造者模式注重的是部件構建的過程,旨在通過一步一步地精確構造創建出一個複雜的物件。
工廠方法模式和建造者模式都屬於物件建立類模式,都用來建立類的物件。但它們之間的區別還是比較明顯的:
- 意圖不同
在工廠方法模式裡,我們關注的是一個產品整體;但在建造者模式中,一個具體產品的產生是依賴各個部件的產生以及裝配順序,它關注的是“由零件一步一步地組裝出產品物件”。簡單地說,工廠模式是一個物件建立的粗線條應用,建造者模式則是通過細線條勾勒出一個複雜物件,關注的是產品組成部分的建立過程。 - 產品的複雜度不同
工廠方法模式建立的產品一般都是單一性質產品,都是一個模樣,而建造者模式建立的則是一個複合產品,它由各個部件複合而成,部件不同產品物件當然不同。這不是說工廠方法模式建立的物件簡單,而是指它們的粒度大小不同。一般來說,工廠方法模式的物件粒度比較粗,建造者模式的產品物件粒度比較細。
二、抽象工廠模式VS建造者模式
抽象工廠模式實現對產品家族的建立,一個產品家族是這樣的一系列產品:具有不同分類維度的產品組合,採用抽象工廠模式則是不需要關心構建過程,只關心什麼產品由什麼工廠生產即可。而建造者模式則是要求按照指定的藍圖建造產品,它的主要目的是通過組裝零配件而產生一個新產品。
三、代理模式VS裝飾模式
裝飾模式就是代理模式的一個特殊應用,兩者的共同點是都具有相同的介面,不同點則是代理模式著重對代理過程的控制,而裝飾模式則是對類的功能進行加強或減弱,它著重類的功能變化。
- 代理模式
是把當前的行為或功能委託給其他物件執行,代理類負責介面限定:是否可以呼叫真實角色,以及是否對傳送到真實角色的訊息進行變形處理,它不對被主題角色(也就是被代理類)的功能做任何處理,保證原汁原味的呼叫。代理模式使用到極致開發就是AOP,是Spring架構開發必然要使用到的技術,它就是使用了代理和反射的技術。 - 裝飾模式
是在要保證介面不變的情況下加強類的功能,它保證的是被修飾的物件功能比原始物件豐富(當然,也可以減弱),但不做准入條件判斷和准入引數過濾,如是否可以執行類的功能,過濾輸入引數是否合規等,這不是裝飾模式關心的。
四、裝飾模式VS介面卡模式
裝飾模式和介面卡模式在通用類圖上沒有太多的相似點,差別比較大,但是它們的功能有相似的地方:都是包裝作用,都是通過委託方式實現其功能。不同點是:裝飾模式包裝的是自己的兄弟類,隸屬於同一個家族(相同介面或父類),介面卡模式則修飾非血緣關係類,把一個非本家族的物件偽裝成本家族的物件,注意是偽裝,因此它的本質還是非相同介面的物件。
- 意圖不同
裝飾模式的意圖是加強物件的功能,不改變類的行為和屬性,只是增加(當然了,減弱類的功能也是可能存在的)功能,使美麗更加美麗,強壯更加強壯,安全更加安全;而介面卡模式關注的則是轉化,它的主要意圖是兩個不同物件之間的轉化。 - 施與物件不同
裝飾模式裝飾的物件必須是自己的同宗,也就是相同的介面或父類,只要在具有相同的屬性和行為的情況下,才能比較行為是增加還是減弱;介面卡模式則必須是兩個不同的物件,因為它著重於轉換,只有兩個不同的物件才有轉換的必要。 - 場景不同
裝飾模式在任何時候都可以使用,只要是想增強類的功能,而介面卡模式則是一個補救模式,一般出現在系統成熟或已經構建完畢的專案中,作為一個緊急處理手段採用。 - 擴充套件性不同
裝飾模式很容易擴充套件!今天不用這個修飾,好,去掉;明天想再使用,好,加上。這都沒有問題。而且裝飾類可以繼續擴充套件下去;但是介面卡模式就不同了,它在兩個不同物件之間架起了一座溝通的橋樑,建立容易,去掉就比較困難了,需要從系統整體考慮是否能夠撤銷。
五、命令模式VS策略模式
命令模式和策略模式的類圖確實很相似,只是命令模式多了一個接收者(Receiver)角色。它們雖然同為行為類模式,但是兩者的區別還是很明顯的。策略模式的意圖是封裝演算法,它認為“演算法”已經是一個完整的、不可拆分的原子業務(注意這裡是原子業務,而不是原子物件),即其意圖是讓這些演算法獨立,並且可以相互替換,讓行為的變化獨立於擁有行為的客戶;而命令模式則是對動作的解耦,把一個動作的執行分為執行物件(接收者角色)、執行行為(命令角色),讓兩者相互獨立而不相互影響。
策略模式和命令模式相似,特別是命令模式退化時,比如無接收者(接收者非常簡單或者接收者是一個Java的基礎操作,無需專門編寫一個接收者),在這種情況下,命令模式和策略模式的類圖完全一樣:
- 關注點不同
策略模式關注的是演算法替換的問題,一個新的演算法投產,舊演算法退休,或者提供多種演算法由呼叫者自己選擇使用,演算法的自由更替是它實現的要點。換句話說,策略模式關注的是演算法的完整性、封裝性,只有具備了這兩個條件才能保證其可以自由切換。
命令模式則關注的是解耦問題,如何讓請求者和執行者解耦是它需要首先解決的,解耦的要求就是把請求的內容封裝為一個一個的命令,由接收者執行。由於封裝成了命令,就同時可以對命令進行多種處理,例如撤銷、記錄等。 - 角色功能不同
策略模式中的抽象演算法和具體演算法與命令模式的接收者非常相似,但是它們的職責不同。策略模式中的具體演算法是負責一個完整演算法邏輯,它是不可再拆分的原子業務單元,一旦變更就是對演算法整體的變更。
而命令模式則不同,它關注命令的實現,也就是功能的實現。例如我們在分支中也提到接收者的變更問題,它隻影響到命令族的變更,對請求者沒有任何影響,從這方面來說,接收者對命令負責,而與請求者無關。命令模式中的接收者只要符合六大設計原則,完全不用關心它是否完成了一個具體邏輯,它的影響範圍也僅僅是抽象命令和具體命令,對它的修改不會擴散到模式外的模組。
當然,如果在命令模式中需要指定接收者,則需要考慮接收者的變化和封裝,例如一個老顧客每次吃飯都點同一個廚師的飯菜,那就必須考慮接收者的抽象化問題。 - 使用場景不同
策略模式適用於演算法要求變換的場景,而命令模式適用於解耦兩個有緊耦合關係的物件場合或者多命令多撤銷的場景。
六、 策略模式VS狀態模式
在行為類設計模式中,狀態模式和策略模式是親兄弟,兩者非常相似,我們先看看兩者的通用類圖,把兩者放在一起比較一下:

策略模式和狀態模式.png
兩個類圖非常相似,都是通過Context類封裝一個具體的行為,都提供了一個封裝的方法,是高擴充套件性的設計模式。但根據兩者的定義,我們發現兩者的區別還是很明顯的:策略模式封裝的是不同的演算法,演算法之間沒有互動,以達到演算法可以自由切換的目的;而狀態模式封裝的是不同的狀態,以達到狀態切換行為隨之發生改變的目的
- 環境角色的職責不同
兩者都有一個叫做Context環境角色的類,但是兩者的區別很大,策略模式的環境角色只是一個委託作用,負責演算法的替換;而狀態模式的環境角色不僅僅是委託行為,它還具有登記狀態變化的功能,與具體的狀態類協作,共同完成狀態切換行為隨之切換的任務。 - 解決問題的重點不同
策略模式旨在解決內部演算法如何改變的問題,也就是將內部演算法的改變對外界的影響降低到最小,它保證的是演算法可以自由地切換;而狀態模式旨在解決內在狀態的改變而引起行為改變的問題,它的出發點是事物的狀態,封裝狀態而暴露行為,一個物件的狀態改變,從外界來看就好像是行為改變。 - 解決問題的方法不同
策略模式只是確保演算法可以自由切換,但是什麼時候用什麼演算法它決定不了;而狀態模式對外暴露的是行為,狀態的變化一般是由環境角色和具體狀態共同完成的,也就是說狀態模式封裝了狀態的變化而暴露了不同的行為或行為結果。 - 應用場景不同
策略模式只是一個演算法的封裝,可以是一個有意義的物件,也可以是一個無意義的邏輯片段,比如MD5加密演算法,它是一個有意義的物件嗎?不是,它只是我們數學上的一個公式的相關實現,它是一個演算法,同時DES演算法、RSA演算法等都是具體的演算法,也就是說它們都是一個抽象演算法的具體實現類,從這點來看策略模式是一系列平行的、可相互替換的演算法封裝後的結果,這就限定了它的應用場景:演算法必須是平行的,否則策略模式就封裝了一堆垃圾,產生了“壞味道”。
狀態模式則要求有一系列狀態發生變化的,它要求的是有狀態且有行為的場景,也就是一個物件必須具有二維(狀態和行為)描述才能採用狀態模式,如果只有狀態而沒有行為,則狀態的變化就失去了意義。 - 複雜度不同
通常策略模式比較簡單,這裡的簡單指的是結構簡單,擴充套件比較容易,而且程式碼也容易閱讀。當然,一個具體的演算法也可以寫得很複雜,只有具備很高深的數學、物理等知識的人才可以看懂,這也是允許的,我們只是說從設計模式的角度來分析,它是很容易被看懂的。而狀態模式則通常比較複雜,因為它要從兩個角色看到一個物件狀態和行為的改變,也就是說它封裝的是變化,要知道變化是無窮盡的,因此相對來說狀態模式通常都比較複雜,涉及面很多,雖然也很容易擴充套件,但是一般不會進行大規模的擴張和修正
七、策略模式VS橋樑模式

策略模式和橋樑模式.png
策略模式是一個行為模式,旨在封裝一系列的行為。而橋樑模式則是解決在不破壞封裝的情況下如何抽取出它的抽象部分和實現部分,它的前提是不破壞封裝,讓抽象部分和實現部分都可以獨立地變化。
簡單來說,策略模式是使用繼承和多型建立一套可以自由切換演算法的模式,橋樑模式是在不破壞封裝的前提下解決抽象和實現都可以獨立擴充套件的模式。橋樑模式必然有兩個“橋墩”——抽象化角色和實現化角色,只要橋墩搭建好,橋就有了,而策略模式只有一個抽象角色,可以沒有實現,也可以有很多實現。
還是很難區分,是吧?多想想兩者的意圖,就可以理解為什麼要建立兩個相似的模式了。我們在做系統設計時,可以不考慮到底使用的是策略模式還是橋樑模式,只要好用,能夠解決問題就成,“不管黑貓白貓,抓住老鼠的就是好貓”。
八、門面模式VS中介者模式
門面模式為複雜的子系統提供一個統一的訪問介面,它定義的是一個高層介面,該介面使得子系統更加容易使用,避免外部模組深入到子系統內部而產生與子系統內部細節耦合的問題。中介者模式使用一箇中介物件來封裝一系列同事物件的互動行為,它使各物件之間不再顯式地引用,從而使其耦合鬆散,建立一個可擴充套件的應用架構。
門面模式是以封裝和隔離為主要任務,而中介者模式則是以調和同事類之間的關係為主,因為要調和,所以具有了部分的業務邏輯控制。兩者的主要區別如下:
- 功能區別
門面模式只是增加了一個門面,它對子系統來說沒有增加任何的功能,子系統若脫離門面模式是完全可以獨立執行的。而中介者模式則增加了業務功能,它把各個同事類中的原有耦合關係移植到了中介者,同事類不可能脫離中介者而獨立存在,除非是想增加系統的複雜性和降低擴充套件性。 - 知曉狀態不同
對門面模式來說,子系統不知道有門面存在,而對中介者來說,每個同事類都知道中介者存在,因為要依靠中介者調和同事之間的關係,它們對中介者非常瞭解。 - 封裝程度不同
門面模式是一種簡單的封裝,所有的請求處理都委託給子系統完成,而中介者模式則需要有一箇中心,由中心協調同事類完成,並且中心本身也完成部分業務,它屬於更進一步的業務功能封裝。
上一篇: ofollow,noindex">設計模式:(四)行為型模式