設計模式的實際應用
1).抽象工廠模式(Abstract factory):
原理:
抽象工廠模式的一個主要目的是把所生成的具體類相分離,這些類的實際名稱被隱藏在工廠中,在客戶級不必了解。
JDK中的此模式應用:
java.util.Calendar#getInstance()
java.util.Arrays#asList()
java.util.ResourceBundle#getBundle()
java.sql.DriverManager#getConnection()
java.sql.Connection#createStatement()
java.sql.Statement#executeQuery()
java.text.NumberFormat#getInstance()
javax.xml.transform.TransformerFactory#newInstance()
應用場合:
1.一個系統要獨立于它的產品的創建、組合和表示時。
2.一個系統要由多個產品系列中的一個來配置時。
3.當你強調一系列相關的產品對象的設計以便進行聯合使用時。
4.當你提供一個產品類庫,而只想顯示他們的接口而不是實現時。
2).建造者/生成器模式 (Builder):
原理:
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
主要用來簡化一個復雜的對象的創建。
JDK中的此模式應用:
java.lang.StringBuilder#append()
java.lang.StringBuffer#append()
java.sql.PreparedStatement
javax.swing.GroupLayout.Group#addComponent()
應用場合:
1.當創建復雜對象的算法應該獨立于該對象的組成部分及他們的裝配方式時。
2.當構造過程必須允許被構造的對象有不同的表示時。
3).工廠方法模式 (Factory Method):
原理:
工廠方法通過一個抽象類實現了所有對產品的加工操作代碼,唯獨將產品的構建方法寫成抽象方法。
繼承這個抽象類的具體類只重寫其構建方法,這樣就實現了對于不同被構建產品復用相同的加工操作邏輯
簡單來說,按照需求返回一個類型的實例。
JDK中的此模式應用:
java.lang.Proxy#newProxyInstance()
java.lang.Object#toString()
java.lang.Class#newInstance()
java.lang.reflect.Array#newInstance()
java.lang.reflect.Constructor#newInstance()
java.lang.Boolean#valueOf(String)
java.lang.Class#forName()
應用場合:
需要在子類中才能決定實例化哪個被操作對象,同時這些被操作對象又復用相同操作邏輯的場合。
4). 原型模式 (Prototype):
原理:
使用自己的實例創建另一個實例。有時候,創建一個實例然后再把已有實例的值拷貝過去,是一個很復雜的動作。
所以,使用這個模式可以避免這樣的復雜性。
JDK中的此模式應用:
java.lang.Object#clone()
java.lang.Cloneable
應用場合:
1.當一個系統應該獨立于它的產品創建、構成和表示時。
2、當要實例化的類是在運行時刻指定時,例如通過動態裝載。
3、為了避免創建一個與產品類層次平行的工廠類層次時。
4、當一個類的實例只能有幾個不同狀態組合中的一種時。
5).單例模式 (Singleton):
原理:
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。通常我們可以讓一個全局變量使得一個對象被訪問,但他不能防止你實例化多個對象,一個最好的辦法就是,讓這個類自身保存它的唯一實例。這個類可以保證沒有其他實例可以被創建,并且它可以提供一個訪問改實例的方法。
JDK中的此模式應用:
java.lang.Runtime#getRuntime()
java.awt.Toolkit#getDefaultToolkit()
java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
java.awt.Desktop#getDesktop()
應用場合:
1.當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時。
2.當這個唯一實例應該是通過子類化可擴展的,并且客戶應該無需更改代碼就能使用一個擴展的實例時。
6).適配器模式 (Adapter):
原理:
將一個類的接口轉換成用戶希望的另一個接口,使原本由于接口不兼容而不能一起工作的那些類可以一起工作。
JDK中的此模式應用:
java.util.Arrays#asList()
javax.swing.JTable(TableModel)
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)
javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()
應用場合:
1.你想使用一個已經存在的類,而它的接口不符合你的要求。
2.你想創建一個可以復用的類,該類可以與其他不相關的類或不可預見的類(即那些接口可能不一定兼容的類)協同工作。
3.(僅適用于對象adapter),你想使用一些已經存在的子類,但是不可能對每一個都進行子類化以匹配他們的接口。對象適配器可以適配它的父類接口
7).橋接模式 (Bridge):
原理:
把抽象和實現解藕,于是接口和實現可在完全獨立開來。
JDK中的此模式應用:
AWT (提供了抽象層映射于實際的操作系統)
JDBC
應用場合:
1.你不希望在抽象和它的實現部分有一個固定的綁定關系。例如這種情況可能是因為程序在運行時刻部分應用可以被選擇或者切換。
2.類的抽象以及它的實現都可以通過生成子類的方法加以擴充。
3.對一個抽象的實現部分的修改應對客戶不產生影響,即客戶端的代碼不必重新編譯。
4.你想在多個對象之間共享實現,但是同時要求客戶并不知道這一點
8).組合模式 (Composite):
原理:
將對象組合成樹形結構以表示"部分-整體"的層次結構。"Composite"使得用戶對單個對象和組合對象的使用具有一致性。
JDK中的此模式應用:
javax.swing.JComponent#add(Component)
java.awt.Container#add(Component)
java.util.Map#putAll(Map)
java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)
應用場合:
1.你想用部分-整體結構層次。
2.你希望用戶忽略組合對象與單個對象的不同,用戶將統一的使用組合結構中的所有對象。
9).裝飾模式 (Decorator):
原理:
動態地給一個對象添加一些額外的職責,比單純的繼承更為靈活合理.
JDK中的此模式應用:
java.io.BufferedInputStream(InputStream)
java.io.DataInputStream(InputStream)
java.io.BufferedOutputStream(OutputStream)
java.util.zip.ZipOutputStream(OutputStream)
java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
應用場合:
比如java的System.IO各種輸出就是通過裝飾模式來實現的,還有一些日志類,動態的添加日志記錄的功能,將耦合度降到最低。
10).外觀模式 (Facade):
原理:
為子系統的一組接口提供一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用
JDK中的此模式應用:
java.lang.Class
javax.faces.webapp.FacesServlet
應用場合:
1.當你要為一個復雜子系統提供一個簡單接口時。子系統往往因為不斷演化而變得越來越復雜。大多數模式使用都會產生更 多更小的類。這使得子系統更具可重用性,也更容易對子系統進行定制,但這也給那些不需要定制子類的的用戶帶來一些 使用上的困難。Facade可以提供一個簡單的缺省視圖,這一視圖對大多數用戶來說已經足夠,而那些需要更多的可定制 性的用戶可以越過Facade層。
2.客戶端程序與抽象類的實現部分存在著很大的依賴性。引入Facade將這個子系統與客戶以及其他的子系統分離,可以提 高子系統的獨立性和可移植性。
3.當你需要構建一個層次結構的子系統時,使用Facade模式定義子系統的每層的入口點。如果子系統之間是相互依賴的, 你可以讓他們僅通過facade進行通訊,從而簡化了他們之間的依賴關系。
11).享元模式 (Flyweight):
原理:
運用共享技術有效地支持大量細粒度的對象。
JDK中的此模式應用:
java.lang.Integer#valueOf(int)
java.lang.Boolean#valueOf(boolean)
java.lang.Byte#valueOf(byte)
java.lang.Character#valueOf(char)
應用場合:
1.一個應用程序使用了大量的對象。
2.完全由大量的對象,造成很大的存儲開銷。
3.對象的大多數狀態都可變為外部狀態。
4.如果刪除對象的外部狀態,那么可以用相對較少的共享對象取代很多組對象。
5.應用程序不依賴于對象標識,由于Flyweight對象可以被共享,對于概念上明顯有別的對象,標識測試將返回真值。
12).代理模式 (Proxy):
原理:
為其他對象提供一種代理以控制對這個對象的訪問,簡單的來說調用這個類的同時其實里面是別的類在干事。
JDK中的此模式應用:
java.lang.reflect.Proxy
RMI
應用場合:
1.遠程代理:也就是為一個對象在不同的地址空間提供局部代表,這樣可以影藏一個對象存在于不同地址空間的事實,比如.net里的webservice。
2.虛擬代理:根據需要將一個資源消耗很大的或者比較復雜的對象延遲到真正需要時才創建,比如延遲加載圖片,優先加載文字
3.保護代理:控制對一個對象的訪問權限,用于對象有權限設置的時候
4.智能引用:當調用真實對象時,代理處額外的事情來,提供額外的服務,如計算對象真實的引用次數,這樣對象沒有引用時可以自動釋放它,通過代理訪問一個對象時做一些額外的內務處理。
13).職責鏈模式 (Chain of responsibility):
原理:
使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系。將這些對象連成一條鏈。
并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。在這個鏈上的所有的對象有相同的接口(抽象類)但卻有不同的實現。
JDK中的此模式應用:
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
應用場合:
1.有多個的對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定。
2.你想在不明確指定接受者的情況下,向多個對象中的一個提交請求。
3.處理一個請求的對象集合應被動態指定。
14).命令模式 (Command):
原理:
將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。
JDK中的此模式應用:
java.lang.Runnable
javax.swing.Action
應用場合:
1.抽象出待執行的動作以參數化某對象。
2.在不同的時刻指定、排列和執行請求。
3.支持取消操作。
4.支持修改日志,這樣當系統崩潰時,這些修改可以被重做一遍。
5.用構建在原語操作上的高層操作構造一個系統。
15).解釋器模式 (Interpreter):
原理:
一個語法解釋器的模式。
JDK中的此模式應用:
java.util.Pattern
java.text.Normalizer
java.text.Format
應用場合:
當一個語言需要解釋執行,并且你可以將該語句中的句子表示為一個抽象語法樹時,可使用解釋器模式。而當存在以下情況時該模式效果最好。
1.該文法簡單對于復雜的文法,文法的類層次變得龐大而無法管理。
2.效率不是一個關鍵問題,最高效的解釋器通常不是通過直接解析語法分析樹實現的,而是首先將他們轉換成另一種形式。
16).迭代器模式 (Iterator):
原理:
提供一種一致的方法來順序遍歷一個容器中的所有元素。
JDK中的此模式應用:
java.util.Iterator
java.util.Enumeration
應用場合:
1.訪問一個聚合對象的內容而無需暴露它的內部表示。
2.支持對聚合對象的多種遍歷。
3.為遍歷不同的聚合結構提供一個統一的接口(即,多態迭代)。
17).中介者模式 (Mediator):
原理:
用中介對象來封裝一系列的對象交互。中介者使各對象不需要顯示地相互引用,從而使其耦合松散,而且可以對立地改變他們之間的交互。用來減少對象單的直接通訊的依賴關系。使用一個中間類來管理消息的方向。
JDK中的此模式應用:
java.util.Timer
java.util.concurrent.Executor#execute()
java.util.concurrent.ExecutorService#submit()
java.lang.reflect.Method#invoke()
應用場合:
1.一組對象以定義良好但是復雜的方式進行通信。產生的相互依賴關系結構混亂且難以理解。
2.一個對象引用很多其他對象并直接與這些對象通信,導致難以復用該對象。
3.想定制一個分部在多個類中的行為,而又不想生成太多的子類。
18).備忘錄模式 (Memento):
原理:
在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態,這樣以后就可將該對象恢復到原先保存的狀態。給一個對象的狀態做一個快照。Date類在內部使用了一個long型來做這個快照。
JDK中的此模式應用:
java.util.Date
java.io.Serializable
應用場合:
1.必須保存一個對象在某一時刻(部分)的狀態,這樣以后需要時它才能恢復到先前的狀態。
2.如果用一個接口來讓其他對象直接得到這個狀態,將會暴露對象的實現細節并破壞對象的封裝性。
19).觀察者模式 (Observer):
原理:
定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并自動更新。
JDK中的此模式應用:
java.util.EventListener
javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionAttributeListener
javax.faces.event.PhaseListener
應用場合:
1.當一個對象有兩個方面,其中一個方面依賴于另一個方面。將二者封裝在獨立的對象中以使他們可以各自獨立的改變和復用。
2.當一個對象的改變需要同時改變其他對象,而不知道具體有多少對象有待改變。
3.當一個對象必須通知其他對象,而又不能假定其他對象是誰。
20).狀態模式 (State):
原理:
這個模式允許你可以在運行時很容易地根據自身內部的狀態改變對象的行為。
JDK中的此模式應用:
java.util.Iterator
javax.faces.lifecycle.LifeCycle#execute()
應用場合:
1.當一個對象的轉換條件表達式過于復雜時,通常這個狀態由一個或者多個枚舉表示,通常有多個操作包含這一相同的的條件結構,state模式將一個條件分支放到一個類中,這使得你可以根據對象自身的情況將對象的狀態作為對象,這一對象不依賴于其他對象而獨立變化,把狀態的判斷邏輯放到表示不同狀態的一系列類中。
2.一個對象的行為取決于它的狀態,并且它必須在運行時根據狀態立即改變行為。
21).策略模式 (Strategy):
原理:
定義一組算法,并把其封裝到一個對象中。然后在運行時,可以靈活的使用其中的一個算法。
JDK中的此模式應用:
java.util.Comparator#compare()
javax.servlet.http.HttpServlet
javax.servlet.Filter#doFilter()
應用場合:
1.多個類只區別在表現行為不同,可以使用Strategy模式,在運行時動態選擇具體要執行的行為。
2.需要在不同情況下使用不同的策略(算法),或者策略還可能在未來用其它方式來實現。
3.對客戶隱藏具體策略(算法)的實現細節,彼此完全獨立。
22).模板方法模式 (Template method):
原理:
使得子類可以不改變一個算法的結構即可以重定義該算法的某些特定步驟
換種說法:允許子類重載部分父類而不需要完全重寫。
JDK中的此模式應用:
java.util.Collections#sort()
java.io.InputStream#skip()
java.io.InputStream#read()
java.util.AbstractList#indexOf()
應用場合:
1.一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。
2.各子類中公共的行為應被提取出來并集中到一個公共類中以避免代碼重復。
首先識別現有代碼的不同之處,并且將不同之處分離為新的操作。
最后,用一個調用這些新的操作的模板方法來替換這些不同的代碼。
3.控制子類的擴展
23).訪問者模式 (Visitor):
原理:
作用于某個對象群中各個對象的操作. 它可以使你在不改變這些對象本身的情況下,定義作用于這些對象的新操作.
JDK中的此模式應用:
javax.lang.model.element.Element 和javax.lang.model.element.ElementVisitor
javax.lang.model.type.TypeMirror 和javax.lang.model.type.TypeVisitor
應用場合:
1.一個對象結構包含很多類對象,他們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作。
2.需要對一個對象中的對象進行很多不同的并且不相關的操作,而你想避免讓這些操作‘污染’這些對象的類。
visitor使得你可以將相關的操作集中起來定義在一個類中。
當該對象結構被很多應用共享時,使用Visitor模式讓每個應用包含需要用到的操作。
3.定義對象結構類很少改變,但經常需要在此結構上定義新的操作。
改變對象結構類需要重定義對所有訪問者的接口,這可能需要很大的代價。
如果對象結構類經常改變,那么可能還是在這些類中定義這些操作較好。
來自:http://www.cnblogs.com/jqbird/tag/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/