原文:http://www.importnew.com/12526.html
本文由 ImportNew - 劉
家財 翻譯自 stackoverflow。歡迎加入Java小組。轉載請參見文章末尾的要求。
提問:我正在學習GoF的《設計模式》,想了解些它們在實際中的應用的例子。大家能給我舉一些使用設計模式的好例子嗎?尤其是在Java類庫中。
贊同最高的回答:
你可以通過Wikipedia對設計模式有個整體上的理解。Wikipedia上也提高了GoF所涉及到的模式。我這裏總結一下,並且儘可能指出在JavaSE與JavaEE的API中是如何運用這些模式的。
創建型設計模式
抽象工廠模式
特點:創建方法返回一個可以用來創建抽象類或接口的工廠類。
- javax.xml.parsers.DocumentBuilderFactory#newInstance()
- javax.xml.transform.TransformerFactory#newInstance()
- javax.xml.xpath.XPathFactory#newInstance()
生成器模式
特點:創建方法返回這個實例本身。
- java.lang.StringBuilder#append()不同步
- java.lang.StringBuffer#append()同步
- java.nio.ByteBuffer#put()(除此之外,還有CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer與DoubleBuffer)
- javax.swing.GroupLayout.Group#addComponent()
- java.lang.Appendable的所有實現
工廠方法模式
特點:創建方法返回抽象類或接口的實現。
- java.util.Calendar#getInstance()
- java.util.ResourceBundle#getBundle()
- java.text.NumberFormat#getInstance()
- java.nio.charset.Charset#forName()
- java.net.URLStreamHandlerFactory#createURLStreamHandler(String)對於每個協議(protocol)返回一個單例對象
原型模式
特點:創建方法返回一個同類型且具有相同屬性的另一個實例。
單例模式
特點:創建方法返回同一個實例(無論在何時調用)。
結構型模式
適配器模式
特點:創建方法接受一個與當前類不同的抽象類或接口的實例作爲參數,返回一個經過修飾或重寫給定參數實例的抽象類或接口的實現。
- java.util.Arrays#asList()
- java.io.InputStreamReader(InputStream)返回一個Reader對象
- java.io.OutputStreamWriter(OutputStream)返回一個Writer對象
- javax.xml.bind.annotation.adapters.XmlAdapter#marshal()與#unmarshal()
橋接模式
特點:創建方法接受一個與當前類不同的抽象類或接口的實例作爲參數,返回一個經過代理或使用給定參數實例的抽象類或接口的實現。
- 暫時沒有想到,一個可以想到的例子是new LinkedHashMap(LinkedHashSet, List),這個方法返回一個不可修改的linkedMap,它就沒有拷貝參數中的元素(item),而是直接使用它們。java.util.Collections#newSetFromMap()和singletonXXX()方法也與之類似。
組合模式
特點:行爲方法把相同抽象類或接口的實例轉化爲一個樹結構。
- java.awt.Container#add(Component)(幾乎對所有的Swing都適用)
- javax.faces.component.UIComponent#getChildren()(幾乎對所有的JSF UI都適用)
裝飾模式
特點:創建方法以一個抽象類或接口的實例爲參數,返回值是增加了額外方法的給參數實例。
- java.io.InputStream、OutputStream、Reader、Writer這些類的所有子類,它們都有一個接受相同類型作爲參數的構造函數。
- java.util.Collections中checkedXXX()、synchronizedXXX()、unmodifiableXXX()方法
- javax.servlet.http.HttpServletRequestWrapper與HttpServletResponseWrapper
外觀模式
特點:行爲方法在內部使用完全不同的抽象類或接口的實例做封裝。
- javax.faces.context.FacesContext,這個類在內部使用了抽象類或接口LifeCycle、ViewHandler、NavigationHandler以及其他一些用戶不需要關心的類(通常這些類都是可通過注入重寫的)。
- javax.faces.context.ExternalContext,這個類在內部使用了ServletContext、HttpSession、HttpServletRequest、HttpServletResponse等。
享元模式
特點:創建方法返回一個緩存的實例,與多例模式有些類似。
代理模式
特點:創建方法返回一個給定抽象類或接口的實例,這個實例代理或使用了這個給定抽象類或接口的另一個實現。
恕我直言,Wikipedia上的類子不是很好,惰性加載實際上和代理模式一點關係也沒有。
行爲模式
職責鏈模式
特點:行爲方法間接調用隊列中同一抽象類或接口的另一實例的同名方法。
命令模式
特點:一個抽象類或接口中的行爲方法調用另一個在創建時經命令方法包裝的抽象類或接口實現的另一個方法。
- java.lang.Runnable的所有實現
- javax.swing.Action的所有實現
解釋器模式
特點:行爲方法返回結構上不同的抽象類或接口的實例,需要注意的是解析或格式化過程並不是這個模式的一部分,而這個過程決定了解釋器如何將要去應用並實施這個變換。
迭代模式
特點:行爲方法連續地返回隊列中的相同對象的不同實例。
- java.util.Iterator類的所有實現(java.util.Scanner也類似)
- java.util.Enumeration類的所有實現
中介者模式
特點:行爲方法接受一個不同的抽象類或接口的實例(一般使用命令模式)作爲參數,而這個參數同時也代理了其它給定抽象類或接口的實例。
- java.util.Timer所有的scheduleXXX()方法
- java.util.concurrent.Executor#execute()
- java.util.concurrent.ExecutorService的invokeXXX()與submit()方法
- java.util.concurrent.ScheduledExecutorService所有scheduleXXX()方法
- java.lang.reflect.Method#invoke()
備忘模式
特點:行爲方法在內部改變整個實例的狀態。
- java.util.Date(setter方法就是典型的例子,Date對象在內容是用一個long值來表示的)
- java.io.Serializable的所有實現
- javax.faces.component.StateHolder的所有實現
觀察者(發佈/訂閱)模式
特點:行爲方法根據其自身的狀態,去調用另一個抽象類或接口實例的方法。
- java.util.Observer/java.util.Observable在實際中用的比較少
- java.util.EventListener的所有實現(幾乎對所以Swing對象都適用)
- javax.servlet.http.HttpSessionBindingListener
- http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionAttributeListener.html
- javax.faces.event.PhaseListener
狀態模式
特點:行爲方法根據它能夠控制的狀態來變自身的行爲。
- javax.faces.lifecycle.LifeCycle#execute()由FacesServlet控制,它的行爲依賴與當前JSF的生命週期所處的階段
策略模式
特點:在一個抽象類或接口的行爲方法會調用作爲一種策略實現而通過參數傳入的另一個抽象類或接口實例的方法。
- java.util.Comparator#compare(),這個方法被Collections#sort()所調用
- javax.servlet.http.HttpServlet類中的service()與所有的doXXX()方法接受HttpServletRequest與HttpServletResponse這兩個參數(並不是通過像成員變量這種方式容納它們),這樣其所有子類都必須去處理它們
- javax.servlet.Filter#doFilter()
模板方法模式
特點:具有由抽象類型定義默認行爲的行爲方法。
- java.io.InputStream、java.io.OutputStream、java.io.Reader與java.io.Writer類的所有非抽象方法
- java.util.AbstractList、java.util.AbstractSet、java.util.AbstractMap的所有非抽象方法
- javax.servlet.http.HttpServlet類的所有doXXX()方法默認發送HTTP 405“方法不允許”這個錯誤給response,你可以自由地選擇是否去實現它們
訪問者模式
特點:由兩個不同的抽象類或接口,它們都有接受對方做參數的方法,被調用的方法會去調用另一個對象的方法,然後根據制定好的策略執行。
- javax.lang.model.element.AnnotationValue與AnnotationValueVisitor
- javax.lang.model.element.Element與ElementVisitor
- javax.lang.model.type.TypeMirror與TypeVisitor