常見設計模式要點總結
前言
最近在看《head first 設計模式》,發現每個章節後的要點總結都是言簡意駭,所以特寫此篇部落格對常見的設計模式要點做個總結。
觀察者模式
在物件之間定義一對多的依賴,這樣一來,當一個物件改變狀態,依賴它的物件都會收到通知,並自動更新
-
觀察者模式定義了物件之間一對多的關係
-
主題(可觀察者)用一個共同對介面來更新觀察者
-
被觀察者不知道觀察者的細節,只知道觀察者實現了觀察者介面
-
多個觀察者時,不可以依賴特定的通知順序
● 抽象主題(Subject)角色: 抽象主題角色把所有對觀察者物件的引用儲存在一個聚集(比如ArrayList物件)裡,每個主題都可以有任何數量的觀察者。抽象主題提供一個介面,可以增加和刪除觀察者物件,抽象主題角色又叫做抽象被觀察者(Observable)角色。
● 具體主題(ConcreteSubject)角色: 將有關狀態存入具體觀察者物件;在具體主題的內部狀態改變時,給所有登記過的觀察者發出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。
● 抽象觀察者(Observer)角色: 為所有的具體觀察者定義一個介面,在得到主題的通知時更新自己,這個介面叫做更新介面。
● 具體觀察者(ConcreteObserver)角色: 儲存與主題的狀態自恰的狀態。具體觀察者角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態 像協調。如果需要,具體觀察者角色可以保持一個指向具體主題物件的引用。
裝飾者模式
動態的將責任加到物件上,想要擴充套件功能,裝飾者提供有別於繼承的另一種選擇
-
裝飾者模式意味著一群裝飾者類,這些類用來包裝具體元件
-
裝飾者類都經過介面或繼承實現
-
可以用無數個裝飾者包裝一個元件
-
裝飾者會導致設計中出現許多小物件,過度使用會讓程式複雜
在裝飾模式中的角色有:
● 抽象構件(Component)角色: 給出一個抽象介面,以規範準備接收附加責任的物件。
● 具體構件(ConcreteComponent)角色: 定義一個將要接收附加責任的類。
● 裝飾(Decorator)角色: 持有一個構件(Component)物件的例項,並定義一個與抽象構件介面一致的介面。
● 具體裝飾(ConcreteDecorator)角色: 負責給構件物件“貼上”附加的責任。
工廠模式
簡單工廠:定義了一個建立物件的介面,但由子類決定要例項化的類是哪一個。
抽象工廠:提供一個介面,用於建立相關或依賴物件的家族而不需要明確指定具體的類
-
所有的工廠都是用來封裝物件的建立
-
工廠方法使用繼承:把物件的建立委託給子類,子類實現工廠方法來建立物件
-
抽象工廠使用物件組合:物件的建立被實現在工廠介面所暴露出來的方法中
-
抽象工廠建立相關的物件家族,不需要依賴他們的具體類
-
依賴倒置原則,依賴於抽象而非具體型別
下圖是簡單工廠模式的uml圖
簡單工廠的關注點是產品,如上圖中的CpuFactory,MainboardFactory。當我們需要新增一個產品的時候(例如memory 就不需要對原有程式碼進行修改),但是當我們需要新增一種cpu的時候(例如huawei cpu)簡單工廠就需要對原有程式碼改動了,於是我們引入第二種抽象工廠。
抽象工廠的關注點是產品族,如上圖中的IntelFactory,AmdFactory。當我們需要新增一個產品族的時候(例如HuaweiFactory 就不需要對原有程式碼進行修改),但是當我們需要新增一種產品的時候(例如memory)抽象工廠就需要對原有程式碼改動了。
以上兩種工廠模式,各有優劣。
單例模式
確保一個類只有一個例項並提供全域性訪問點
-
單例模式確保程式中一個類最多隻有一個實現
-
單例模式提供訪問者合格例項對全域性訪問點
-
Java中實現單例模式需要私有構造器, 一個靜態方法和一個靜態變數
-
必須假設所有的程式都是多執行緒的,考慮併發的問題
-
如果使用多個類載入器,可能導致單例模式失效產生多個例項
推薦一種單例模式的最佳實踐
publicclassSingleTon{ privateSingleTon(){} privatestaticclassInstanceHolder{ privatefinalstaticSingleTonsingleTon=newSingleTon(); } publicSingleTongetSingleTon(){ returnInstanceHolder.singleTon; } }複製程式碼
介面卡模式/門面模式
介面卡模式:將一個類的介面轉換成期望的另一個介面,介面卡讓原本不相容的類可以合作無間
門面模式:提供了一個統一的介面用來訪問子系統的一群介面。外觀定義了一個高層介面使得子系統更加易用
-
當需要使用一個現有的類而其介面並不符合你的需要時,使用介面卡
-
介面卡將一個物件包裝起來以改變其介面,裝飾者將一個物件包裝起來以增加新的行為和責任,門面模式將一群物件“包裝”簡化其介面
-
當需要簡化並同意一個很大的介面或者一群複雜的介面時使用門面模式
-
門面模式可以從一個複雜的子系統中解耦
-
使用一個門面模式需要將子系統組合進外觀中,然後將工作委託給子系統執行
介面卡uml圖
模式所涉及的角色有:
● 目標(Target)角色: 這就是所期待得到的介面。注意:由於這裡討論的是類介面卡模式,因此目標不可以是類。
● 源(Adapee)角色: 現在需要適配的介面。
● 介面卡(Adaper)角色: 介面卡類是本模式的核心。介面卡把源介面轉換成目標介面。顯然,這一角色不可以是介面,而必須是具體類
門面模式相對比較簡單
上圖是我暑假在阿里實習做的一個小需求。其中核身元件就用到了門面模式,將核身元件這個領域物件暴露給前端,使得前端不必關注具體的每個核身項,從一個複雜的子系統中解耦。
代理模式
一個替身或佔位符以訪問這個物件
-
代理模式為另一個物件提供代表,以便控制客戶對物件的訪問
-
代理在結構上類似裝飾者但目的不同
-
裝飾者模式為物件加上行為,而代理則是控制訪問
在代理模式中的角色:
● 抽象物件角色: 聲明瞭目標物件和代理物件的共同介面,這樣一來在任何可以使用目標物件的地方都可以使用代理物件。
● 目標物件角色: 定義了代理物件所代表的目標物件。
● 代理物件角色: 代理物件內部含有目標物件的引用,從而可以在任何時候操作目標物件;代理物件提供一個與目標物件相同的介面,以便可以在任何時候替代目標物件。代理物件通常在客戶端呼叫傳遞給目標物件之前或之後,執行某個操作,而不是單純地將呼叫傳遞給目標物件。
總結
想要學習設計模式的初衷是,如何寫出更靈活,更健壯,更符合規範的程式碼。也確實從設計模式的學習中感受到了面向物件的強大,不過紙上得來終覺淺,絕知此事要躬行。
參考文件:
《Head First 設計模式》
[23種設計模式的深入理解] https://www.cnblogs.com/foryang/p/5849402.html 23種設計模式的深入理解