java
design pattern
設計模式是指在軟體發展中,已經經過驗證來解決在特定的環境下、重複出現的或是特定問題的解決方案。
設計模式並不能解決所有問題,而只是解決「特定問題」,在這些問題「重複出現」的情況下,重用設計模式就可以解決那些特定問題;但設計模式並不是萬靈丹,也要避免過度使用、過度設計造成的軟體的架構過於複雜。
設計模式也無法直接用來完成程式碼的編寫,而是描述在各種不同情況下,要怎麼解決問題的一種方案。
設計模式最有名的莫過於GoF合作出版的「設計模式:可復用物件導向軟體的基礎」一書裡面的23種設計模式,至今都被奉為聖經般存在。
補充
GoF(英語,Gang of Four,簡稱GoF),Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides四個人 合作出版了「設計模式:可復用物件導向軟體的基礎」一書。
但該書作為聖經其實頗為艱深並不容易閱讀,後來市面上其實也出了很多關於設計模式的書籍,就比較像是「聖經」的「解說版」,會比較容易理解,建議初學者可以先看市面上的其他書籍。
GoF將23種設計模式分成了三大類:
一、創建型模式(Creational)
根據合適的情況來建立物件。單純的建立物件常會導致一些設計問題或增加設計的複雜度。創建型模式則藉由控制物件的生成方式來解決這問題。
設計模式 | 目的 | 生活案例 | 框架源碼舉例 |
---|---|---|---|
工廠模式(Factory) | 封裝創建細節 | 實體工廠 | LoggerFactory、Calender |
單例模式(Singleton) | 保證獨一無二 | CEO | BeanFactory、Runtime |
原型模式(Prototype) | 高效創建對象 | 克隆 | ArrayList、PrototypeBean |
建造者模式(Builder) | 開放個性配置步驟 | 選配 | StringBuilder、BeanDefinationBuilder |
二、結構型模式(Structural)
適合不同情境下的物件間關係結構,藉由從上到下的方式來了解元件間的關係,以簡化設計。
設計模式 | 目的 | 生活案例 | 框架源碼舉例 |
---|---|---|---|
代理模式(Proxy) | 增強職責 | 媒婆 | ProxyFactoryBean、JdkDynamicAopProxy、CglibAopProxy |
門面模式(Facade) | 統一訪問入口 | 前台、導診台 | JdbcUtils、RequestFacade |
裝飾器模式(Decorator) | 靈活擴展、同宗同源 | 煎餅 | BufferedReader、InputStream |
享元模式(Flyweight) | 共享資源池 | 全國社保聯網 | String、Integer、ObjectPool |
組合模式(Composite) | 統一整體和個體 | 組織架構樹 | HashMap、SqlNode |
適配器模式(Adapter) | 兼容轉換 | 電源適配 | AdvisorAdapter(Spring AoP)、HandlerAdapter(SpringMVC) |
橋接模式(Bridge) | 不允許用繼承 | 橋 | DriverManager |
三、行為型模式(Behavioral)
物件之間的合作行為構成的程式行為,物件之間若有設計良好的行為互動,可以使得程式執行時更有效率,且職責更為清晰、整個程式的結構將更有彈性。
設計模式 | 目的 | 生活案例 | 框架源碼舉例 |
---|---|---|---|
委派模式(Delegate) | 只對結果負責 | 授權委託書 | ClassLoader、BeanDefinitionParserDelegate |
模板模式(Template) | 邏輯復用 | 把大象裝進冰箱的步驟 | JdbcTemplate、HttpServlet |
策略模式(Strategy) | 選擇支付方式 | Comparator、InstantiationStrategy | |
責任鏈模式(Chain of Responsibility) | 解耦處理邏輯 | 踢皮球 | FilterChain、Pipeline |
迭代器模式(Iterator) | 統一對集合的訪問方式 | 統一刷臉進站 | Iterator |
命令模式(Command) | 解耦請求和處理 | 遙控器 | Runnable、TestCase |
狀態模式(State) | 綁定狀態和行為 | 訂單狀態跟蹤 | Lifecycle |
備忘錄模式(Memento) | 備份 | 草稿箱 | StateManageableMessageContext |
中介者模式(Mediator) | 統一管理網狀資源 | 朋友圈 | Timer |
解釋器模式(Interpreter) | 實現特定語法解析 | 摩斯密碼 | Pattern、ExpressionParser |
觀察者模式(Observer) | 解耦觀察者與被觀察者 | 鬧鐘 | ContextLoaderListener |
訪問者模式(Visitor) | 解耦數據結構和數據操作 | KPI考核 | FileVisitor、BeanDefinitionVisitor |
單例模式(Singleton),其定義為:只有一個實例,而且自行實例化並向整個系統提供這個實例。
補充
適合場景為存取IO和資料庫等資源時,適合使用該模式,例如像資料庫連線通常只要一個就夠了,多個連線容易造成資料庫負擔,或是在同一個程式內,過多的資料庫連線,也會造成系統資源的負擔。
積極模式在宣告靜態物件的時候就已經初始化。
懶散模式(Lazy)在呼叫getInstance時才進行初始化,且非執行緒安全,可以在getInstance()方法上加上synchronized來達到執行緒安全,但是這樣做的話效率會很低。
上面這段程式碼看起來只有一段,但其實不是原子操作,這句程式碼會被編譯成多條組合指令,大致上做了三件事:
但是由於Java編譯器允許失序執行,所以 2. 和 3. 的順序是無法保證的,有可能 1-2-3 也有可能 1-3-2 。如果在 3. 執行完畢、2. 還沒執行之前,切換到線程B,那instance已經不是null,此時B取走instance再使用就會出錯。
可以確保線程安全,保證物件唯一性,並且延遲實例化,所以推薦使用。
可讀性並不是很高,較少使用。
單例模式