寫在前面:
學習過程中不僅要熟練掌握技能,理論的消化吸收也必不可少。雖然個人更傾向於學習技術類的東西(短時間的精力投入很快就能看到成效...),但看了很多前輩的經驗總結后才知道理論性的東西是絕對不能忽視的,畢竟理論對實踐有着重要的指導意義。而了解“設計”相關的東西,會對“實現”產生潛移默化的影響,雖然不能在短時間內看到讓人欣喜的變化,但可能有一天回過頭來一想“哦~,原來我這個不錯的小習慣是當年在那本書上學到的啊”
一.什么是設計模式?
繞了一圈之后讓我們又回到這個話題吧(看書之前問自己一遍,看完之后再問自己一遍,答案之間的差異就是感悟了)
之前:
自問:設計模式是什么?
自答:是一些系統設計的指導原則吧,不過我現在天天寫代碼,應該也用不到設計層面上的東西。
自問:哦,那具體是什么?
自答:不清楚,不過我見過一些前輩的代碼,結構很復雜,一看就很上檔次的那種,那些應該就用了設計模式吧,所以代碼有沒有應用設計模式應該就是高手與新手的區別了。等我成了高手之后,這種東西還不信手拈來,嗯,不說了,我寫代碼去了,好好積累項目經驗。
...
之后:
自問:設計模式是什么?
自答:設計模式是由代碼結構優化經驗萃取出來的理論知識,應用成熟的設計模式能夠增強代碼的可復用性、可擴展性與可維護性。
自問:你好像很專業的樣子,那好,既然設計模式有這么多好處,那是不是應用了設計模式的設計都是好設計?
自答:當然不是,我們不能為了使用模式而使用模式。設計模式可不能濫用,畢竟應用設計模式必須要作出一些犧牲(比如增加類結構的復雜性...),所以濫用設計模式的話是會出事的。而且,就算我們有了錘子,也不能把所有問題都看作釘子吧?
...
P.S.還記得學習正則表達式的總結:能不用就盡量不要用(最大限度的避免濫用),設計模式與之類似,不能看到什么問題都往模式上靠,只有當我們非常確定在當前情景下確實需要用設計模式來優化我們的設計時,才考慮使用設計模式(至於到底用不用,還要權衡重構的成本與優化的收益...)
二.要不要使用設計模式?
這是個值得思考的問題,畢竟現在我們已經擁有了一把錘子,要不要用它當然成了問題,畢竟不是所有的問題都可以用錘子來解決。退一步講,即便所有問題都能用錘子解決,我們也不確定使用錘子是不是最好的解決方案(拔釘子的話,可能用鉗子更好些...)
當我們拿着某個設計模式想放進我們的代碼中時,最好權衡一下利弊,誠然,設計模式具有的設計上的彈性一定會給我們之后的維護變更帶來些便利。但是利與弊到底哪個更多一些,我們需要先回答幾個問題再做決定:
- 我們的項目是不是幾乎不涉及維護或者沒有后續版本,那么我們引入設計模式還有必要嗎?
- 我們項目的規模是不是大到了不用設計模式不行的地步?
- 這個設計模式用在這里合適嗎?有沒有更合適的?
- 非要用設計模式嗎?可不可以用幾個簡單的設計原則來代替?
- 引入設計模式之后,代碼結構的復雜度大大增加,重構的成本我們可以接受嗎?
如果深思熟慮之后,還是覺得使用設計模式比較好,那么,放心去用吧,之后好好享受設計模式帶來的好處吧
三.設計原則總結
設計原則都是一些簡單的指導意見,沒有固定的實現,因而設計原則也更加靈活,常見的設計原則如下:
- 封裝變化(把易於發生變化的部分抽出來,以減少其變化對其它部分的影響)
- 多用組合,少用繼承(組合比繼承更有彈性)
- 針對接口編程,不針對實現編程(使用接口可以避免直接依賴具體類)
- 為交互對象之間的松耦合設計而努力(更松的耦合意味着更多的彈性)
- 類應該對擴展開放,對修改關閉(open-close原則)
- 依賴抽象,不要依賴具體類(減少對具體類的直接依賴)
- 只和朋友交談(密友原則)
- 別找我,我會找你(Don't call me, I will call you back.安卓開發的大原則)
- 類應該只有一個改變的理由(單一責任原則)
能用設計原則解決的問題就不要用設計模式(殺雞焉用宰牛刀...),因為設計原則實現起來更加靈活,更加輕巧(不用去考慮模式的條條框框...)
四.設計模式總結
| 名稱 | 特點 |
| 策略模式(Strategy) | 把可以替換的算法步驟封裝成一個個算法族,供運行時動態選擇 |
| 觀察者模式(Observer) | 定義並維護對象之間的一對多關系 |
| 裝飾者模式(Decorator) | 建立擁有共同超類的裝飾者與被裝飾者來實現功能的動態擴展 |
| 工廠模式(Factory) | 封裝對象的創建過程,包括工廠方法模式和抽象工廠模式 |
| 單件(例)模式(Singleton) | 用來創建唯一的對象(比如數據庫連接對象,線程池對象等等) |
| 命令模式(Command) | 封裝方法調用細節,解耦請求者與執行者 |
| 適配器模式(Adapter) | 用來實現不同接口間的轉換 |
| 外觀模式(Facade) | 為復雜的子系統提供簡單易用的高層接口 |
| 模版方法模式(Template Method) | 用來封裝算法骨架(流程),某些步驟由子類實現 |
| 迭代器模式(Iterator) | 用來封裝遍歷細節 |
| 組合模式(Composite) | 提供一種層級結構,使得我們能夠忽略對象與對象集合間的差異,一視同仁地對待它們 |
| 狀態模式(State) | 把所有動作都封裝在狀態對象中,狀態持有者將行為委托給當前狀態對象 |
| 代理模式(Proxy) | 通過插入第三方(代理對象)來分離調用者和被調用者(不同於執行者) |
| 復合模式(Compound) | 將多個模式組合結合起來形成一個“框架”,以解決一般性問題 |
| 橋接模式(Bridge) | 將抽象的控制類與具體實現類通過組合解耦,使得抽象層類與實現層類可以對立與對方而變化 |
| 生成器模式(Builder) | 用來封裝組合結構(樹形結構)的構造過程,與迭代器模式類似,都隱藏了組合結構的內部實現,只提供一組用於創建組合結構的接口 |
| 責任鏈模式(Chain of Responsibility) | 讓一個請求可以被一組接收者順序處理,類似於Android處理請求的方式:一個接收者捕獲請求后可以return true消費掉請求,也可以return false傳遞給接收者隊列中的下一個接收者(觀察者) |
| 蠅量模式(Flyweight) | 抽象出對象管理層來統一管理大量的同類型對象,以減少運行時對象實例的個數,減少內存消耗 |
| 解釋器模式(Interpreter) | 用來為簡單語言創建解釋器,將語法規則直接映射為各個類,結構簡單,但效率較低 |
| 中介者模式(Mediator) | 引入中介者來封裝多個對象間的復雜交互,以降低同級(在類結構統一層次上的)對象間的依賴 |
| 備忘錄模式(Memento) | 支持對象狀態的保存與恢復,並將對象狀態數據封裝起來,獨立於客戶代碼以提供保護(Java中可以結合序列化反序列化技術來實現該模式) |
| 原型模式(Prototype) | 以現有的對象為原型,通過clone得到新的對象(以簡化新對象的創建過程) |
| 訪問者模式(Visitor) | 為組合結構添加新的操作,而不需要頻繁的改變組合結構 |
五.面向對象的設計(Object Oriented Design)
一直伴隨着OOD的問題就是“折衷”(或者說是“取舍”),最簡單的例子——要不要用設計模式?
- 用,意味着將產生復雜的類關系,多層的抽象,我們將犧牲易讀性換取易擴展性、易維護性或者其它特性
- 不用,意味着我們不需要對現有代碼進行重構(或者不用去在復雜的設計上耗費過多的時間),但使用設計模式的所有好處我們就都享受不到了
二者選其一,這就是一個“取舍”,或者創造第三個選項(比如使用設計原則),這就是一個“折衷”
寫在后面:關於《Head First設計模式》
很少寫書評,因為每個人的喜好不同,不好作推薦(甚至有時候喜歡一本書僅僅是因為喜歡作者的行文風格而已,從而不自覺的認為書籍內容不錯。。)
這本書是前輩推薦的,看完之后覺得大部分章節講的很不錯,既細致又通俗,但感覺某些章節並不是很好(比如第一章策略模式的例子不很貼切,和后面的遠程代理部分細節展開的不合理)
總體來說,作為入門書籍的話,《Head First設計模式》還是不錯的,個人感受,僅供參考
