《headfirst設計模式》筆記
總結
基礎
抽象
封裝
多型
繼承
原則
封裝變化
多用組合,少用繼承
針對介面程式設計,不針對實現程式設計
為互動物件之間的鬆耦合設計而努力
對擴充套件開放,對修改關閉
依賴抽象,不要依賴具體類
只和朋友交流
別找我,我會找你
類應該只有一個改變的理由
模式
策略模式
策略模式,定義演算法族,分別封裝起來,讓它們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。
觀察者模式
在物件之間定義一對多的依賴,這樣一來,當這個物件改變狀態,依賴它的物件都會受到通知,並自動更新。代表MVC
裝飾者模式
動態將責任附加到物件上,想要擴充套件功能,裝飾者提供有別於繼承的另一種選擇。代表JAVA中IO(INPUTStream系列)
抽象工廠模式
提供一個介面,用於建立相關或依賴物件的家族,而不需要明確指定具體類。
工廠方法模式
定義了一個建立物件的介面,但由子類決定要例項化的類是哪一個。工廠方法讓類把例項化推遲到子類。
單例模式
確保一個類只有一個例項,並提供全域性訪問點。
命令模式
將請求封裝成物件,這可以讓你使用不同的請求、佇列、或者日誌請求來引數化其物件。命令模式也可以支援撤銷操作
介面卡模式
將一個類的介面,轉換成客戶期望的另一個介面。介面卡讓原本不相容的類可以合作無間
外觀模式(門面模式)
提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更加容易使用。
模板方法模式(Template)
在一個方法中定義了一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使的子類可以在不改變演算法的結構的情況下,重新定義演算法中的某一些步驟。
迭代器模式(Iterator)
提供一種方法順序訪問一個聚合物件中各個元素,而又不暴露其內部的表示
組合模式(Composite)
執行你將物件組成樹形結構表現“整體/部分”的層次結構。組合能讓客戶以一致的方式處理個別對象和物件組合。
狀態模式(STATE)
允許物件在內部狀態改變時改變它的行為,物件看起來好像修改了它的類
代理模式(proxy)
為另一個物件提供一個替身或佔位符以訪問這個物件
複合模式
複合模式結合兩個或以上的模式,組成一個解決方案,解決一再發生的一般性問題。
設計模式入門
使用模式對的最好方式:把模式裝進腦子裡,然後在你的設計和已有的應用中,尋找何處可以使用他們。
- 找出應用中可能需要變化之處,把他們獨立出來,不要和那些不需要變化的程式碼混在一起。
- 針對介面程式設計,而不是針對實現程式設計。針對介面程式設計,就是針對超型別程式設計。
- 變數的宣告應該是超型別:比如抽象類或者一個介面。
- 有一個(組合)可能比是一個更好
- 多用組合,少用繼承.類的行為不是通過繼承得到而是通過組合得到的。
策略模式(Strategy)
定義了演算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。
類的行為就可以看做是演算法
觀察者模式(Observe)讓你的物件知悉現況
類比報紙、雜誌的訂閱
觀察者模式
定義了物件之間的一對多依賴,這樣一來,當一個物件改變狀態時,它的所有依賴者都會收到通知並自動更新。 Swing大量使用觀察者模式,許多GUI框架也是如此。
java內建觀察者模式
JAVA API有內建的觀察者模式。java.util包內包含了最基本的Observer介面與Observable類,甚至可以使用推拉模式。
可觀察者如何送出通知
- 先呼叫setChanged()方法,標記狀態已經改變的事實
- 然後呼叫兩種notifyObservers()方法中的一個:notifyObservers()或notifyObservers(Object arg),這個版本可以傳送任何資料物件給每一個觀察者
觀察者如何接受通知
觀察者實現了更新方法,但是方法的簽名不一樣。
update(Observable o,Object arg)
1. Observable:主題本身當做第一個變數,好讓觀察者知道是哪個主題通知它的。
2. arg這正是傳入notifyObservers()的資料,如果沒有說明則為空
setChanged()方法用來標記狀態已經改變的事實,好讓notifyObservers()知道當它被呼叫時應該更新觀察者。如果呼叫notifyObservers()之前沒有先呼叫setchanged(),觀察者就不會被通知。
java.util.Observable的暗黑面
Observable是以類,不是介面,必須被繼承。
setChanged()方法是protect的,只有繼承才能呼叫。
裝飾者模式(Decorator)
類應該對拓展開放,對修改關閉
舉例:以飲料為主體,然後執行時以調料來“裝飾”飲料。
- 裝飾者和被裝飾者物件有相同的超型別。
- 你可以用一個或多個裝飾者包裝一個物件
- 裝飾者可以在所委託被裝飾者的行為之前或之後,加上自己的行為
- 物件可以在任何時候被裝飾
裝飾者模式
動態地將責任附加到物件上,若有拓展功能,裝飾者提供了比繼承更有彈性的替代方案。 真實世界的裝飾者:java I/O
裝飾者模式缺點
有大量的小類,數量比較多
原則
對拓展開放,對修改關閉
工廠模式(Factory)
利用靜態方法定義一個簡單的工廠,這是很常見的技巧,常被稱為靜態工廠。為何使用靜態方法?因為不需要使用建立物件的方法來例項化物件。但是有一個缺點,不能通過繼承來改變建立方法的行為
定義簡單工廠
簡單工廠其實不是一個設計模式,應該算是一種程式設計習慣。 設計模式中,所謂“實現一個介面”並不一定表是寫一個類,並利用implement關鍵字來實現某個Java介面。“實現一個介面”泛指實現某個超型別(可以試類或介面)
所有工廠模式都用來封裝物件的建立。工廠方法模式(Factory Method Pattern)通過讓子類決定該建立的物件是什麼,來達到將物件建立的過程封裝的目的。
定義工廠方法模式
工廠方法模式:定義一個建立物件的介面,但由子類決定要例項化的類是哪一個。工廠方法讓類把例項化推遲到子類
簡單工廠把全部的事情,在一個地方都處理完了,然而工廠方法卻是建立一個框架,讓子類決定要如何實心。簡單工廠的做法,是將物件的建立封裝起來,簡單工廠不具備工廠方法的彈性。
要依賴抽象,不要依賴具體類
多依賴抽象類,而不依賴具體類。 依賴倒置:是底層元件依賴於抽象高層的抽象。
定義抽象工廠模式
抽象工廠模式:提供一個介面,用於建立相關或依賴物件的家族,而不需要明確指定具體類
總結
依賴抽象,不要依賴具體類
- 所有的工廠都是用來封裝物件的建立
- 簡單工廠,雖然不是真正的涉及模式,但是也是一個簡單的方法,實現將客戶程式從具體類解耦
- 工廠方法使用繼承:把物件的建立委託給子類,子類實現工廠方法來建立物件
- 抽象工廠使用物件的組合:物件的建立被實現在工廠介面所暴露出來的方法中
- 抽象工廠建立相關的物件家族,而不需要依賴它們具體類。
- 簡單理解就是抽象工廠由多個工廠方法組成
單例模式(singleton)
用來建立獨一無二的,只能有一個例項的物件。比如執行緒池、記憶體、配置表。
單例模式也提供一個全域性訪問點,和全域性變數。但是不是程式一開始就建立物件。
JVM實現:在用到的時候才建立物件
經典的單間模式實現
public class Singleton{
private static Singleton uniqueInstance;//利用靜態變數記錄唯一例項
private Singleton(){//私有構造器宣告為私有,只有Singleton類才可以呼叫構造器
}
public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
如果我們不需要這個例項,它就永遠不會產生
單例模式
確保一個類只有一個例項,並提供一個全域性訪問點
處理多執行緒問題
把getInstance()變成同步(synchronized)方法,就可以解決多執行緒
public class Singleton{
private static Singleton uniqueInstance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqeuInstance;
}
}
誠然,這種方式會影響效能。可以有如下選擇:
- 如果getInstance()的效能對應用程式不是很關鍵,就什麼都別做。這樣做簡單高效
- 如果建立單例,對程式負擔不重,就不用延遲例項化的做法
pulbic static Singleton uniqueInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return uniqueInstance;
}
- 用雙重檢查加鎖,在getInstance()中減少使用同步 利用雙重檢查加鎖,首先檢查是否建立了,未建立,才進行同步,只有一次同步機會。
public class Singleton{
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
if(uniqueInstance==null){
synchronized(Singleton.class){
if(uniqueInstance==null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
注意:volatile關鍵字確保:當uniqueInstance變數被初始化,多個執行緒能處理uniqueInstance變數。必須在1.5及以上才能使用。
關於多個類載入器可能有機會各自建立自己的單價例項
每個類載入器都定義了一個名稱空間。如果有兩個以上的類載入器,不同的類載入器可能會載入同一個類,從整個程式來看,同一個類會被載入多次。如果是單例模式的類,就會產生多個單例並存。解決辦法:自行指定類載入器,並指定同一個類載入器。
java1.2以後單例模式不會被垃圾回收器回收。放心使用
總結
- 單例模式確保程式中一個類最多隻有一個例項
- 單例模式也是提供訪問這個例項的全域性點
- 在java實現單例模式需要私有構造器、一個靜態方法和一個靜態變數
- 確定在效能和資源的限制上,小心選擇適當的方案來實現單例。
- 如果不是採用java 5以上,雙重檢查會失效。
- 使用JVM1.2或之前的版本,必須建立單件登錄檔,以免垃圾收集器將單件回收
命令模式(command)——封裝呼叫
將方法呼叫(method invocation)封裝起來 通過封裝方法呼叫哦,可以記錄日誌、或者實現撤銷undo 命令模式可以將“動作的請求者”從“動作的執行者”物件中解耦
命令模式
將“請求”封裝成物件,以便使用不同的請求、佇列或者日誌來引數化其他物件。命令模式也支援可撤銷操作。
在許多設計模式中都會看到空物件的使用。甚至有些時候,空物件本身也被視為是一種設計模式
總結
- 命令模式將發出請求的物件和執行請求的物件解耦
- 在被解耦的兩者之間是通過命令物件進行溝通的。命令物件封裝了接受者的一個或一組動作
- 呼叫者通過呼叫命令物件的excute()發出請求,這會使得接受者的動作被呼叫
- 呼叫者可以接受命令當做引數,甚至在執行時動態地進行
- 命令可以支援撤銷,做法是實現一個undo()方法來回到excute()被執行前的狀態。
- 巨集命令是命令的一種簡單延伸,允許呼叫多個命令。巨集方法也可以支援撤銷
- 實際操作時,很常見使用命令物件,也可以直接實現請求,而不是將工作委託給接受者。
- 命令可以用來實現日誌和事物系統。
介面卡模式(Adapter)與外觀模式(Facade,也叫門面模式)
裝飾者模式將物件包裝起來,並賦予它們新的職責。而現在是將某些物件包裝起來,將類的介面轉換成自己想要的介面
需要讓一個介面卡包裝多個被適配者,這就是外觀模式
定義介面卡模式
將一個類的介面,轉換成客戶期望的另一介面。介面卡讓原本介面不相容的類可以合作無間。
1. 類介面卡使用多重繼承,物件介面卡使用組合
2. 物件介面卡使用組合,可以適配該類的任何子類
3.
裝飾者和介面卡
- 當事情涉及到裝飾者,就表示一些新的行為或責任要加入到你的設計中。
外觀模式和介面卡模式的差異不在於它們包裝了幾個類,而是在於它們的意圖,介面卡模式的意圖是“改變”介面符合客戶的期望;而外觀模式的意圖是提供子系統的一個簡化介面。
定義外觀模式
提供一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
最少知識原則
告訴我們要減少物件之間的互動,只留下幾個密友
總結
- 當需要使用一個現有的類而其介面不符合我的需求時,就使用介面卡
- 當需要簡化並統一一個很大的介面或者一群複雜的介面時,使用外觀
- 介面卡改變介面以符合客戶的期望
- 外觀將客戶從一個複雜的子系統中解耦
- 實現一個介面卡可能需要一番功夫,與目標介面的大小和複雜程度有關
- 實現一個外觀,需要將子系統組合進外觀中,然後將工作委託給子系統來執行
- 介面卡模式有兩種形式:物件介面卡和類介面卡。類介面卡需要用到多重繼承
- 你可以為一個子系統實現一個以上的外觀
- 介面卡將一個物件包裝起來以改變其介面;裝飾者將一個物件包裝起來以增加新的行為和責任,而外觀將一群物件“包裝”起來以簡化介面。
模板方法模式 封裝演算法(Template)
直到目前,我們議題都繞著封裝轉;我們已經封裝了物件的建立、方法的呼叫、複雜介面。接下來我們要封裝演算法塊
模板方法定義了一個演算法的步驟,並允許子類為一個或多個步驟提供實現
定義模板方法模式
在一個方法中定義了一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使的子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟
1. 當你的子類必須提供演算法中的某個方法或步驟的實現時,就使用抽象方法。如果演算法的這個部分是可選的,就使用鉤子,如果是鉤子的話,子類可以選擇實現這個鉤子
2. 好萊塢法則:別調用高層,讓高層選擇呼叫
3. applet大量使用了模板方法模式
總結
- 模板方法定義了演算法的步驟,把這些步驟的實現延遲到了子類
- 模板方法模式為我們提供了一種程式碼複用的重要技巧。
- 模板方法的抽象類可以定義具體方法、抽象方法和鉤子
- 抽象方法由子類實現
- 鉤子是一種方法,它在抽象類中不做事,或者只做預設的事情,子類可以選擇要不要去覆蓋它
- 為了防止子類改變模板方法中的演算法,可以將模板方法宣告為final
- 好萊塢原則告訴我們,將決策權放在高層模組中,以便決定如何以及何時呼叫底層模組
- 策略模式和模板方法模式都封裝演算法,一個用組合一個用繼承
- 工廠方法是模板方法的一種特殊版本
管理良好的集合 迭代器(Iterator)與組合模式(Composite)
封裝變化的部分
1. 如果不允許一個方法,可以丟擲一個java.lang.UnsupportedOperationException執行時異常
定義迭代器模式
提供一種方法順序訪問一個聚合物件中的各個元素,而又不暴露其內部的表示。 迭代器模式把元素之間的遊走的責任交給迭代器,而不是聚合物件。這不僅讓聚合的介面和實現變得更簡潔,也可以讓聚合更專注在它所應該專注的事情上面
迭代器意味著沒有次序。只是取出所有的元素,並不表示取出元素的先後就代表元素的大小次序。對於迭代器來說,資料結構可以有次序或是沒有次序,甚至資料是可以重複的。除非某個集合檔案有特別說明,否則不可以對迭代器所取出的元素大小順序做出假設
單一責任
類的每個責任都有改變的潛在區域。超過一個責任,意味著超過一個改變的區域。這個原則告訴我們,儘量讓每個類保持單一責任
#### java5的迭代器和集合
java5中包含了一種新形式的for語句,稱為for/in.這可以讓你在一個集合或者一個數組中遍歷,而且不需要顯式建立迭代器
```
for(Object:collection){
}
```
定義組合模式(composite)
允許你將物件組合成樹形結構來表現“整體/部分”層次結構。組合能讓客戶以一致的方式處理個別對象以及物件組合
使用組合結構,我們能把相同的操作應用在組合和個別物件上。換句話說,在大多數情況下,我們可以忽略物件組合和個別物件之間的差別
總結
- 迭代器允許訪問聚合的元素,而不需要暴露它的內部結構
- 迭代器將遍歷聚合的工作封裝進一個物件中。
- 當使用迭代器的時候,我們依賴聚合提供遍歷
- 迭代器提供了一個通用的介面,讓我們遍歷聚合的項時,就可以使用多型機制
- 組合模式提供一個結構,可同時包容個別物件和組合物件
- 組合模式允許客戶對個別物件以及組合物件一視同仁
- 組合結構內的任意物件稱為元件,元件可以是組合,也可以是葉節點
狀態模式(事物的狀態)state
狀態通過改變物件內部的狀態來幫助物件控制自己的行為
定義狀態模式
允許物件在內部狀態改變時改變它的行為,物件看起來好像修改了它的類
將狀態封裝稱為獨立的類,並將動作委託到代表當前狀態的物件,我們知道行為會隨著內部狀態而改變
總結
- 狀態模式允許一個物件基於內部狀態而擁有不同的行為
- 和程式狀態機PSM不同,狀態模式用類代表狀態
- Context會將行為委託給當前狀態物件
- 通過將每個狀態封裝進一個類,我們把以後需要做的任何改變發區域性化了
- 狀態模式和策略模式有相同的類圖,但是它們的意圖不同
- 策略模式通常會用行為或演算法來配置Context類
- 狀態模式允許Context隨著狀態的改變而改變行為
- 狀態轉換可以由STATE類或Context類控制
- 使用狀態模式通常會導致設計中類的數目大量增加
- 狀態類可以被過個Context例項共享
代理模式(Proxy)控制物件的訪問
代理要做的就是:控制和管理訪問 遠端物件:是一種物件,活在不同java虛擬機器(JVM)堆中或者說,在不同的地址空間執行的遠端物件
製作遠端服務
- 製作遠端介面 遠端介面定義出可以讓客戶遠端呼叫的方法
- 製作遠端實現 為遠端介面中定義遠端方法提供真正的實現
- 利用rmic產生的stub和skeleton。這是客戶和服務的輔助類,不需要建立這些類
- 啟動RMI registry 可以從中查詢代理的位置
- 開始遠端服務 服務實現類去例項化一個服務的例項,並將這個服務註冊到RMI registry
製作遠端介面
- 拓展java.rmi.Remote remote不具有方法,只是一個標記
- 宣告所有的方法都會丟擲RemoteException
- 確定變數和返回值屬於原語型別或者序列化型別。遠端方法的變數和返回值,必須屬於原語型別或Serializable型別。這不難理解。遠端方法的變數必須被打包並通過網路運送,這要靠序列化來完成。如果你使用原語型別、字串和許多API中內定的型別,都不會有問題。如果你傳送自己定義的類,就必須保證你的類實現了Serializable
製作遠端實現
- 實現遠端介面 你的服務必須實現遠端介面,也就是客戶將要呼叫的方法介面
- 拓展UnicastRemoteObject 為了要成為遠端服務物件,你的物件需要某些“遠端”功能。最簡單的就是拓展UnicastRemoteObject,讓超類幫你做這些工作
- 設計一個不帶變數的構造器,並宣告RemoteException
- 用RMI REgistry註冊此服務 當註冊這個實現物件時,RMI系統其實註冊的是stub,因為這是客戶真正需要的。註冊服務使用了java.rmi.Naming類的靜態rebind()方法
產生Stub和Skeleton
在遠端實現類上執行rmic rmic 是JDK內一個工具,用來為一個服務類產生stub和skeleton。
執行remiregistry
開啟一個終端,啟動remiregistry
啟動服務
開啟另一個終端,啟動服務
工作方式
- 客戶到RMI registry中尋找
Naming.lookup("rmi://127.0.0.1/RemoteHello")
- RMI registry返回Stub物件 作為lookup方法的返回值,然後RMI會自動對Stub反序列化。你在客戶端必須有stub類,否則stub就無法被反序列化
- 客戶呼叫stub的方法,就像stub就是真正的服務物件一樣
注意:
1. 忘了在啟動遠端服務之前先啟動rmiregistry
2. 忘了讓變數和返回值的型別成為可序列化的型別
3. 忘了給客戶提供stub類
transient關鍵字,這樣就告訴JVM不要序列化這個欄位
定義代理模式
為另一個物件提供一個替身或佔位符以控制對這個物件的訪問。 控制訪問是客戶端不知道如何訪問真正的物件。
幾種代理控制訪問的方式
1. 遠端代理控制訪問遠端物件
2. 虛擬代理控制訪問建立開銷大的資源
3. 保護代理基於許可權控制對資源的訪問
虛擬代理作為建立開銷大的物件的代表。虛擬代理經常直到我們真正需要一個物件的時候才建立它。當物件在建立前和建立中時,由虛擬代理來扮演物件的替身。物件建立後,代理就會將請求直接委託給物件。
使用JAVA API代理建立保護代理
java在java.lang.reflect包中有自己的代理支援,利用這個包你可以在執行時動態地建立一個代理類,實現一個或多個介面,並將方法的呼叫轉發到你所指定的類。動態代理,需要執行方法放在InvocationHandler中。
要點
- 代理模式為另一個物件提供代表,以便控制客戶對物件的訪問,管理訪問的方式有許多種
- 遠端代理管理客戶和遠端物件之間的互動
- 虛擬代理控制訪問示例化開銷大的物件
- 保護代理基於呼叫者控制對物件方法的訪問
- 代理模式有許多變體,例如:快取代理、同步代理、防火牆代理和寫入時複製代理
- 代理在結構上類似裝飾者
- 裝飾者模式為物件加上行為,而代理則是控制訪問
- java內建的代理支援,可以根據需要建立動態代理,並將所有呼叫分配到所選的處理器
- 和其他的包裝者(wrapper)一樣,代理會造成你的設計中類的數目增加
複合模式 模式的模式
由不同模式構成模式。複合模式代表是MVC 複合模式在一個解決方案中結合兩個或多個模式,以解決一般或重複發生的問題。 MVC是數個模式的結合
MVC模式
- 模型利用觀察者讓控制器和檢視可以隨最新的狀態改變而更新。控制器是檢視的行為
- 檢視和控制器實現了經典的策略模式:檢視是一個物件,可以被調整使用不同的策略,而控制器提供了策略。 Model 2是MVC在WEB上的調整
總結
- mvc是複合模式,結合了觀察者模式、策略模式和組合模式
- 模型使用了觀察者模式,以便觀察者更新,同時保持兩者之間的解耦
- 控制器是檢視的策略,檢視可以使用不同的控制器實現,得到不同的行為
- 檢視使用組合模式實現使用者介面,使用者介面通常組合了巢狀的元件,像面板、框架和按鈕
- 這些模式攜手合作,把MVC模型的三層解耦,保持設計乾淨又有彈性
- 介面卡模式用來將新的模型適配成已有的檢視和控制器
- model2是MVC在web上的應用,在model2中,控制器實現成Servlet,而JSP/html是檢視
複合模式
複合模式結合兩個及兩個或以上的模式,組成一個解決方案,解決一再發生的一般性問題。
與設計模式相處——真實世界中的模式
模式
在某情景下,針對某問題的某種解決方案
- 情景就是應用某個模式的情況,這應該是會不斷出現的情況
- 問題就是你想在某情景下達到的目標,但也可以是某情景下的約束
- 解決方案就是你所追求的,一個通用的設計。
建立型模式
建立型模式涉及到將物件例項化,這類模式都提供一個方法,將客戶從所需要例項化的物件中解耦
行為型模式
都涉及到類和物件如何互動及分配職責
結構型模式
可以讓你把類或物件組合到更大的結構中
保持簡單
設計時,儘可能用最簡單的方式解決問題,你的目標應該是簡單
重構的時間就是模式的時間
重構就是通過改變你的程式碼來改進它的組織方式的過程。目標是要改善其結構而不是其行為。應該將思緒集中在設計本身,而不是模式上,只有真正需要時才使用模式,有些時候簡單的方式就行得通,那麼就不要用模式
反模式
告訴你如何採用一個不好的解決方案解決一個問題。反模式看起來總像是一個好的解決方案,但是當它真正被採用後,就會帶來麻煩。通過將反模式歸檔,我們能夠幫助其他人在實現它們之前,分辨出不好的解決方案。 反模式有它自己的誘惑,但是在長遠來看會造成不好的影響。反模式除了告訴你不好之外,也給你提出建議的解決方案。
- 模式能夠帶來最大的好處之一是:讓你的團隊擁有共享詞彙。
其它模式
橋接模式(Bridge)
使用橋接模式不只改變你的實現,也改變你的抽象
責任鏈模式(Chain of Responsibility Pattern)
當你想要讓一個以上的物件有機會能夠處理某個請求的時候,就使用責任鏈模式
享元模式(蠅量模式 Flyweight Pattern)
如想讓某個類的一個例項能用來提供許多“虛擬例項”,就使用享元模式。 享元模式的用途和缺點
- 當一個類有許多的例項,而這些例項能被同一方法控制的時候,我們就可以使用享元模式
- 享元模式的缺點在於,一旦你實現了它,那麼單個邏輯例項將無法擁有獨立而不同的行為。
中介者 (Mediator pattern)
使用中介者模式(Mediator Pattern)來集中相關物件之間的複雜的溝通和控制方式。
中介者的優點
1. 通過將物件彼此解耦,可以增加物件的複用性
2. 通過將控制邏輯集中,可以簡化系統維護
3. 可以讓物件之間所傳遞的訊息變得簡單而且大幅減少
中介者的用途和缺點
1. 中介者常常被用來協調相關的GUI元件
2. 中介者模式的缺點是,如果設計不當,中介者物件本身會變的過於複雜
備忘錄(Memento Pattern)
當你需要讓物件返回之前的狀態時(例如,你的使用者請求“撤銷”),就使用備忘錄模式
備忘錄的用途和缺點
1. 備忘錄用於儲存狀態
2. 使用備忘錄的缺點:儲存和恢復狀態的過程可能相當耗時
3. 在java系統中,其實可以考慮使用序列化機制儲存系統的狀態
原型模式(prototype)
當建立給定類的例項的過程很昂貴或很複雜時,就使用原型模式
訪問者模式
當你想要為一個物件的組合增加新的能力,且封裝並不重要時,就使用訪問者模式(Visitor Pattern)
訪問者的優點
1. 允許你對組合結構加入新的操作,而無需改變結構本身。
2. 想要加入新的操作,相對容易
3. 訪問者所進行的操作,其程式碼是集中在一起的
訪問者的用途和缺點
1. 當採用訪問者模式的時候,就會打破組合類的封裝
2. 因為遊走的功能牽涉其中,所以對組合結構的改變就更加困難