對於任何還不熟悉設計模式的人來說,在對這個領域進行簡短的縱覽之後,可能會留下這樣的印象:設計模式是一個市場營銷大騙局,它不過是一些簡單的編程技術,或者不過是計算機科學家的玩物。盡管這些印象都有那麼一點道理,然而設計模式的確是職業C++程序員工具箱中不可或缺的組件。
設計模式是一個被反復談論的架構主題。它為特定上下文中的常見設計問題提供了解決方案,並描述了這種解決方案的結果。設計模式不僅僅是對技術的簡單描述,它還是從現有的成功實踐一點一滴匯集起來的設計智慧的具名封裝,並以窬交流和復用的方式編寫而成。模式關乎程序員之間的順暢交流。
從實踐的角度來看,設計模式具有兩個重要的屬性。首先,它們描述了經過驗證的、成功的設計技術,這些技術可以按上下文相關的方式進行定制,以便滿足新的設計場合的要求。其次,並且可能更重要的是,在提及某個特定的應用時,不僅包括其中用到的技術,還包括應用該模式的動因以及應用後所達到的效果。
這類事物並不是什麼新東西。考慮一個來自算法領域的類比。考慮如下聲明:“有一個未排序的序列,必須要進行很多次搜索。因此,希望對其進行快速排序,並且使用二分查找來執行每一個查找。”能夠使用術語“快速排序”和“二分查找”,這種價值是不可估量的,不但在設計方面如此,在就該設計與受過教育的同事進行交流時也如此。當我說“快速排序”時,我的同事知道我正在排序的序列具有隨機存取結構,並且它的排序時間復雜度的O(nlog2n),同時該序列中的元素可以采用類似小於操作符進行比較。當我說“二分查找”時,我的同事知道序列已經被排序過了,定位感興趣的元素所執行的比較操作的時間復雜度為O(log2n),並且存在一個適當的操作來對序列中的元素進行比較。標准算法所具有的共享的知識以及標准詞匯表,不但允許高效地記錄文檔,而且允許對設計方案進行有效的評議。比如說,如果我計劃對一個單向鏈接表結構來執行這個查找和排序過程,我的同事立刻會自鳴得意地哈哈大笑,並指出在這種情況下我不能使用快速排序並且可能不希望使用二分查找。
在設計模式出現之前,在對面向對象設計的文檔化、交流以及高效地評議方面,這些優點都不具備。我們被迫低水平地描述我們的設計,這種方式低效且不夠精確。這並不是說用於復雜面向對象設計的技術尚不存在,而是這些技術尚未以一個共享的、通用術語的方式為整個編程社群所用。設計模式解決了這個問題,我們現在可以像描述算法設計一樣高效、毫無歧義地描述面向對象設計。
舉個例子,當我們看到Bridge模式被應用到某項設計中時,我們知道在一個簡單的機制層面,抽象數據類型實現被分離成一個接口類和一個實現類。此外,我們知道這樣做的原因是為了將接口從實現強有力地分離出來,這樣,對實現的改變將不會影響到使用接口的用戶。我們還知道這種分離會帶來運行期開銷,知道應該怎樣對抽象數據類型的源代碼進行布局,還知道許多其它細節。模式的名字是關於某項技術的諸多信息和經驗的高效且無歧義的“句柄”,在設計和文檔中小心並正確地使用模式和模式術語,可以使代碼和設計更加明確。
那些嚴謹的模式專家有時以某種文獻的形式來描述模式,這種描述遵循某種正式的結構。還有幾種常見的變體也在使用,但不管哪種描述方式,均包含下面4個必不可少的部分:
首先,設計模式必須具有一個毫無歧義的名字。例如,術語“包裝器(Wrapper)“對於設計模式命名來說就沒有什麼意義,因為它早已被廣泛使用並且具有許多不同的含義。使用“Wrapper”這樣的術語來命名某種設計模式只會帶來混淆和誤解。實際做法是:以前在"Wrapper"名下的設計技術指派為"Bridge" "Strategy" "Facade" "Object Adapter"以及其它一些模式名字。使用精確的模式名字比使用不那麼精確的名字具有“明顯”的優勢,就像術語“二分查找”比“查找”更精確一樣。
其次,模式描述必須定義該模式所能解決的問題。這種描述可以相對寬泛,也可以相對狹窄。
再次,模式描述要記述該問題的解決方案。根據陳述的問題,該解決方案可以相對高級,也可以相對低級,但無論如何,它應該具有足夠的通用性,以便可以根據問題可能出現的不同上下文進行定制。
最後,模式描述要記述將該模式應用於某個上下文的後果。在應用該模式後,該上下文是如何發生改變的?不管是變好,還是變壞。
擁有模式的知識可以使一名糟糕的設計師搖身一變成為一名優秀的設計師嗎?呃,是給出另一個類比的時候了,設想你被迫學習某一門讓人痛苦的數學課,它的期末考試內容是證明某個領域中的許多定理。如果才能從這門課中死裡逃生呢?當然,最顯而易見的方式是成為一個天才。它從最初的原理開始,進而研究整個數學分支的基礎知識,最終證明那些定理。一個更為實際的途徑是,你牢記並消化該數學領域中的大量定理,並使用它所具備的任何天賦的數學能力、靈感以及好運去選擇適當的輔助定理,然後以某種邏輯“膠水”將它們粘合在一起,從而最終證明新的定理。是的,甚至對於那些“傳送中的天才”來說,這種方式都是很有優勢的,因為基於現成的定理來證明會更高效,同“凡夫俗子”交流起來也更容易。當然,熟悉輔助定理並不能保證一個可憐的學數學的學生通過考試,但這類知識至少可以使其能夠理解別人給出的證明。
同樣的道理,從最初的原理進而到復雜的面向對象設計也是頗為無趣的,而且與他人交流最終設計也很困難。組合使用各種設計模式來生成面向對象設計,類似於在數學中使用輔助定理來證明一個新的定理。設計模式常常被描述為“微架構(Micro-architecture)“,它們可以與其它模式進行組合從而生成一個新的架構。當然,選擇適當的模式並有效地對其進行組合,也是需要設計方面的專家經驗和天資禀賦的。不過,一旦設計完成後,甚至你的經理都能夠理解完整的設計方案,只要他具備一些必需的模式方面的知識即可。