為什麼需要模式#
程式設計中的許多決策是獨特的——開發網站和開發心律調節器截然不同。然而,當決策越來越偏向純技術層面時,一種熟悉感油然而生:「我是不是剛寫過這段程式?」
如果程式設計師能在日常重複的部分花費更少時間和精力,就能有更多資源去做好真正獨特的問題。
程式的基本法則#
大多數程式遵循一小組法則:
- 程式被閱讀的次數遠多於被撰寫的次數
- 沒有所謂的「完成」——後續修改的投入遠超初始開發
- 程式使用一組基本的**狀態(State)和控制流(Control Flow)**概念來組織結構
- 讀者需要在細節和概念之間理解程式,有時從細節到概念,有時從概念到細節
模式的組成#
模式(Pattern)建立在這些共通性之上。以迴圈(Loop)為例:
- 每個程式設計師都必須決定如何組織迭代
- 當你思考如何寫迴圈時,大多數領域特定的問題已暫時解決,剩下的是純技術議題
- 迴圈應該:易讀、易寫、易驗證、易修改、高效
這些關注點的列表就是模式的起點。上述的約束或力量(Forces)影響著程式中每個迴圈的寫法。這些力量可預測地反覆出現——這就是模式之所以稱為模式的一個含義:它是一種力量的模式(Pattern of Forces)。
模式如何運作#
每個模式都呈現了對各種力量相對優先順序的觀點:
- 撰寫迴圈有幾種合理的方式,每種方式暗示了約束之間不同的優先順序
- 如果效能更重要,迴圈的組織方式會不同;如果易修改性更重要,結構又會不同
- 大多數模式附帶一小篇論述,討論替代方案,並解釋為何推薦的解法較優
揭示模式建議背後的推理,能讓讀者自行判斷如何處理反覆出現的問題。
每個模式也附帶一個解法的種子。例如,集合迭代的模式可能建議:「使用 Java 5 的 for 迴圈來表達迭代。」模式在抽象原則與實踐之間架起橋樑,幫助你撰寫程式碼。
模式的協作#
模式之間相互協作:
- 建議使用
for迴圈的模式引出了「如何命名迴圈變數」的問題 - 與其將所有內容塞進單一模式,另一個模式專門涵蓋變數命名
- 本書中模式的呈現風格差異頗大:有些模式有明確的名稱和分節討論,較小的模式則嵌入在較大的模式中,可能只需一兩句話的說明
模式如同習慣#
使用模式有時會感到受限,但模式能節省時間與精力:
- 就像鋪床——按照習慣做比每次重新思考每個步驟要省力得多
- 你有一套鋪床的既定模式,大幅簡化了這項雜務
- 如果床靠牆或床單太小,你會調整策略,但整體上可以按照慣例完成,讓心思留給更有趣的任務
- 當一個模式成為習慣後,不必每次寫迴圈都發起一場辯論
- 如果整個團隊對某個模式感到不滿,可以討論引入新模式的選項
沒有任何一組模式適用於所有程式設計情境。 盲目複製任何人的風格,不如思考並練習自己的風格,並在團隊內討論和分享。
模式作為決策輔助#
- 模式最適合作為人類決策的輔助工具
- 某些實作模式最終會被納入程式語言中——正如
setjmp()/longjmp()的結構化使用演變成了今天的例外處理(Exception Handling)系統 - 在那之前,模式通常需要在使用前進行調適(Adaptation)
總結#
使用模式幫助程式設計師為常見問題撰寫合理的解法,留出更多時間、精力和創造力應用於真正獨特的問題:
- 每個模式將一個常見的程式設計問題與影響因素的討論綑綁在一起
- 提供關於如何快速建立令人滿意的解法的具體建議
- 結果是:在程式的無聊部分做得更好 / 更便宜 / 更快,在每個程式獨特的問題上投入更多時間和精力
下一章「A Theory of Programming」描述了這些實作模式所依據的價值觀與原則。