PHP程式員閱讀Java語言實現設計模式的書,然後用Go語言實現。配以現實生活中的實例,幫助理解設計模式。本篇包括:策略、觀察者、裝飾者、工廠、單例、命令、適配器、外觀。 ...
前言
最近讀了《Head First 設計模式》,每天早上看一章,學習一個設計模式,做些筆記,然後晚上抽空用剛學習的 Go 語言實現一下。半個月下來書讀完了,留下了一些筆記,寫博客總結一下。
書中的例子都是 Java 寫的,但幾乎沒使用 Java 語言的特性,很容易看懂。對於我來說,就是一個 PHP 開發工程師,讀了一本 用 Java 語言實現設計模式的書,然後用 Go 寫了一遍。。。=_=
本文為每個設計模式只分配了一小節,總結一下設計模式的概念和特點以及適用場景,並介紹了自己用代碼實現時的列舉的例子,用現實生活中的事物對比加深一下記憶 ( 代碼實現中所有的例子都是自己原創的,有牽強的部分,不要介意)。每個模式篇幅不大,可以給新人入門,給瞭解過設計模式的人作為速查。
文章經常被人爬,而且還不註明原地址,我在這裡的更新和糾錯沒法同步,這裡註明一下原文地址:http://www.cnblogs.com/zhenbianshu/p/7406572.html 以防誤人子弟。
放上 Go 實現設計模式的 源碼地址:DesignPattern-枕邊書-Github ,偶有更新,歡迎 star
。OK,正文開始。
策略模式(Strategy)
介紹
策略模式: 將演算法或操作抽象成實現共同介面、可以被替換
的類,實現邏輯和具體演算法的解耦。
- 將各種行為
抽象成演算法
,封裝演算法為對象; - 演算法實現
共同介面
,調用者調用時不考慮演算法具體實現,調用介面方法即可; - 調用者可隨時替換此演算法對象;
場景
- 多個方法擇一使用,且他們會被隨時替換;
- 方法沒有共性,使用繼承會有大量重寫,使用介面會有大量重覆使用;
實現
- 兩個演算法: 冒泡排序和快速排序;
- 抽象冒泡排序和快速排序為演算法對象,實現演算法介面,擁有 used() 被使用方法;
- 計算器計算時不用理會是什麼演算法,調用 used() 即可;
觀察者模式(Observer)
介紹
觀察者模式:主題主動向觀察者推送
變化,解決觀察者對主題對象的依賴。
- 觀察者實現
被通知
介面,併在主題上註冊,主題只保存觀察者的引用
,不關心觀察者的實現; - 在主題有變化時調用觀察者的通知介面來通知已註冊的觀察者;
- 通知方式有
推
(主題變化時將變化數據推送給觀察者)和拉
(主題只告知變化,觀察者主動來拉取數據);
場景
- 一個主題,多個觀察者,主題的任何變動,觀察者都要第一時刻得到;
- 觀察者獲取主題變化困難,定時不及時,輪詢消耗大;
- 觀察者可以隨時停止關註某主題;
實現
- 張三和李四是記者,他們需要及時瞭解城市發生的新聞;
- 張三和李四在電視臺註冊了自己的信息;
- 城市發生了新聞,電視臺遍歷註冊信息,通知了張三和李四;
- 李四退休了,在電視臺註銷了自己的信息;
- 城市又發生了新聞,電視臺只通知了張三;
裝飾者模式(Decorator)
介紹
裝飾者模式:包裝一個對象,在被裝飾對象的基礎上添加功能
;
- 裝飾者與被裝飾對象擁有同一個超類,
裝飾者擁有被裝飾對象的所有外部介面
,可被調用,外界無法感知調用的是裝飾者還是被裝飾者; - 裝飾者需要被裝飾者作為參數傳入,併在裝飾者內部,在
被裝飾者實現的基礎上添加或修改某些功能
後,提供同被裝飾者一樣的介面; - 裝飾者也可被另一個裝飾者裝飾,即嵌套裝飾;
- 裝飾者是一群包裝類,由於裝飾的複雜性,會多出很多個裝飾者小類;
場景
- 對象需要動態地添加和修改功能;
- 功能改變後不影響原對象的使用;
實現
- 在商店內,花作為被裝飾者對象、紅絲帶和盒子作為花的裝飾者;
- 花、紅絲帶、盒子有共同的超類“商品”,他們都能被賣掉;
- 我們可以在紅絲帶裝飾過花後,再用盒子再包裝一次;
- 包裝後的花,顧客買時也不會受到任何影響;
工廠模式(Factory)
介紹
工廠模式: 顧名思義,工廠模式是對象的生產器
,解耦用戶對具體對象的依賴。
- 實現
依賴倒置
,讓用戶通過一個產品工廠
依賴產品的抽象
,而不是一個具體的產品; - 簡單工廠模式:接收參數並根據參數創建對應類,將對象的實例化和具體使用解耦;
- 抽象工廠模式:將工廠
抽象出多個生產介面
,不同類型的工廠調用生產介面時,生產不同類型的對象; - 簡單工廠常配合抽象工廠一起使用;
場景
- 根據不同條件需求不同的對象;
- 對象實例化的代碼經常需要修改;
實現
- 簡單工廠:向鞋廠內傳入不同的類型(布制),鞋廠會生產出不同類型的鞋子(布鞋);
- 抽象工廠:有兩座鞋廠:李寧鞋廠、Adidas鞋廠,他們能生產對應各自品牌的鞋子;
- 搭配使用:向不同的抽象工廠(李寧)傳入不同的類型(運動類型),會生產出對應品牌對應類型的鞋子(李寧運動鞋);
單例模式(Singleton)
介紹
單例模式:保證同一個類全局只有一個實例對象
;
- 在第一次實例化後會使用
靜態變數保存
實例,後續全局使用此靜態變數; - 一般將構造方法私有化,構造方法添加 final 關鍵字無法被重寫,添加一個類靜態方法用於返回此實例;
- 在多線程時應該考慮
併發
問題,防止兩次調用都被判定為實例未初始化而重覆初始化對象;
場景
- 全局共用同一個實例對象(資料庫連接等);
- 某一處對此對象的更新全局可見;
實現
- 利用 Go 中包的可見性規則來隱藏對象的實例化許可權;
- 使用包變數保存實例對象,獲取實例時判斷是否已實例化,如為nil,實例化對象並返回,如有值,直接返回值;
- 待用鎖實現 Go routine 併發時的問題;
命令模式(Command)
介紹
命令模式:將一個命令封裝成對象
,解耦命令的發起者和執行者。
- 命令對象實現
命令介面(excute[、undo])
,命令發起者實例化命令對象,並傳遞此對象,並不關心此對象由誰執行; - 命令執行者只負責調用命令對象的執行方法即可,不關心對象是由誰生成的;
- 與策略模式不同之處:策略模式是通過不同的演算法做同一件事情(例如排序),而命令模式則是通過不同的命令做不同的事情;
場景
- 命令發起者與執行者無法直接接觸;
- 命令需要撤銷功能,卻不易保存命令執行狀態信息時;
實現
- 指揮官創建了一個“從樹下跑到草地上”的命令;
- 命令被分配給張三執行,張三作為軍人,接到命令後不管命令的具體內容,而是直接調用命令的執行介面執行;
- 指揮官發佈了撤銷指令,張三又從草地上跑到了樹下;
適配器模式(Adapter)
介紹
適配器模式:包裝對象提供一個介面,以適配調用者
。
- 適配器通過一個中間對象,
封裝目標介面
以適應調用者
調用; - 調用者調用此適配器,以達到調用目標介面的目的;
- 適配器模式與裝飾者模式的不同之處:適配器模式不改變介面的功能,而裝飾者會添加或修改原介面功能;
場景
- 提供的介面與調用者調用的其他的介面都不一致;
- 為一個特殊介面修改調用者的調用方式得不償失;
實現
- 張三是個正常人,他能通過說話直接地表達自己;
- 李四是個聾啞人,他沒法直接表達自己,但他會寫字;
- 筆記本作為一個適配器,用筆記本“包裝”了李四之後,當李四需要表達自己想法時,調用筆記本的“表達”功能,筆記本再調用李四“寫字”的方法;
外觀模式(Facade)
介紹
外觀模式:通過封裝多個複雜的介面
來提供一個簡化介面
來實現一個複雜功能。
- 外觀模式是通過封裝多個介面來將介面
簡單化
; - 外觀模式不會改變原有的多個複雜的單一介面,這些介面依然能被單獨調用,只是提供了一個額外的介面;
- 外觀模式與適配器模式的不同之處:外觀模式是
整合
多個介面並添加
一個簡化介面,適配器是適配一個介面;
場景
- 實現某一功能需要調用多個複雜介面;
- 經常需要實現此功能;
實現
- 正常的沖咖啡步驟是:磨咖啡豆、燒開水、倒開水攪拌咖啡。
- 我們經常需要直接沖咖啡,而不是使用單一步驟,每次喝咖啡時調用三個方法很麻煩;
- 封裝三個介面,額外提供一個 “沖咖啡” 的方法,需要喝咖啡時只需要調用一次沖咖啡方法即可;
小結
《Head First 設計模式》這書真心不錯,例子很輕鬆,給人很多時間和空間來思考,同時介紹模式時使用結合故事,層層深入的方法,讓人印象很深刻,推薦。
書中詳細介紹了 14 個基礎設計模式,還有 9 個簡化版,就自己查資料結合自己的理解來總結了。
本系統準備寫三篇,敬請期待中下篇。
關於本文有什麼問題可以在下麵留言交流,如果您覺得本文對您有幫助,可以點擊下麵的 推薦 支持一下我。博客一直在更新,歡迎 關註 。