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