《Design Patterns 設計模式(GoF)》Podcast 準備稿:設計模式是什麼與核心思想
書名: 設計模式 Design Patterns(Elements of Reusable Object-Oriented Software) 作者: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides(Gang of Four) 系列: 啃一本大書(恩普拉氏) 公開標題建議: 啃一本大書|Design Patterns.先別急著背模式,先搞懂這幾條原則 (1/11) 涵蓋範圍: 導論(第1章)— 什麼是 Design Pattern、四要素、三大設計原則
背景速覽
這是「啃一本大書」系列裡,分量最重、影響最深遠的一本之一。《Design Patterns》(1994) 由四位作者合寫,江湖人稱 Gang of Four(GoF,四人幫),整本書就一個目標:把資深物件導向設計師腦袋裡那些「講不太清楚但一直在用」的設計經驗,整理成 23 個有名字、有結構、可以拿出來討論的「模式」。
這集是整季的起手式,先不碰任何具體模式。我們要先把地基打穩:什麼叫 design pattern、它包含哪四個要素、以及全書真正的靈魂——那三條反覆出現的設計原則。把這集講透,後面 23 個模式你會發現它們其實是同一套思想的不同變奏。
一句話重點
GoF 真正的貢獻不是「發明」了 23 個模式,而是給它們取了名字、建立了一套共同語彙;而比模式本身更重要的,是支撐它們的三條設計原則——找出會變與不變的部分並封裝變化、優先用組合而非繼承、針對介面而非實作寫程式。
值得討論的重點
1. 什麼是 Design Pattern:一個有名字的「問題—解法」配對
GoF 借用建築師 Christopher Alexander 的定義:每個 pattern 描述一個反覆出現的問題,以及那個問題的核心解法——核心到你可以用它一百萬次,而每次的具體長相都不完全一樣。
書裡定義每個模式都有四個要素,這四個要素就是整本書的「履歷表格式」:
- Pattern Name(名稱)——一兩個詞講清楚這個設計。這看似最小,其實最關鍵(後面會展開)。
- Problem(問題)——什麼時候該用、前提條件是什麼。
- Solution(解法)——參與的元素、職責、協作關係。注意:它是模板,不是可以直接複製貼上的程式碼。
- Consequences(後果/權衡)——用了會得到什麼、犧牲什麼。這欄是專業與業餘的分水嶺。
要先替聽眾澄清一個層級問題:GoF 的模式不是 linked list 那種可以直接編碼重用的資料結構,也不是整個系統的架構,而是夾在中間的「特定情境下、一般性設計問題的、class 與物件如何溝通」這個抽象層級。
2. 三條核心原則(這集的主菜,也是全書真正的脊椎)
GoF 在導論裡反覆敲三件事,我會把它當成整季的「定錨原則」:
- 針對介面而非實作寫程式(Program to an interface, not an implementation)——變數別宣告成具體 class,只依賴抽象介面所定義的行為。這樣 client 跟具體型別解耦,run-time 才能多型替換。
- 優先組合而非繼承(Favor object composition over class inheritance)——GoF 直接點名:設計師有「過度使用繼承」的傾向。繼承是白箱重用(父類內部對子類可見,會破壞封裝、父類一動子類連坐);組合是黑箱重用(透過介面互動、run-time 可替換)。23 個模式裡有一大票,本質就是「把某個原本要靠繼承解決的東西,改成抱一個物件進來」。
- 封裝會變化的概念(Encapsulate the concept that varies)——這是最高層的那條。找出設計裡「未來會變」的那一塊,把它隔離、包成獨立物件。Strategy 封裝演算法、State 封裝狀態、Abstract Factory 封裝「要建哪一家族的物件」——全都是這條原則的化身。
我會用一句話收這三條:模式都是手段,原則才是目的。
3. 模式怎麼分類,以及它們彼此有關係
GoF 用兩個維度分類 23 個模式:
- Purpose(目的):Creational(建立物件)、Structural(組合物件)、Behavioral(物件互動與職責分配)。
- Scope(範圍):Class pattern(靠繼承、compile-time、靜態)vs Object pattern(靠物件關係、run-time、動態)——絕大多數都是 object pattern。
而且要強調:模式不是孤島。它們會一起用(Composite + Iterator)、會互為替代(Prototype vs Abstract Factory)、會結構相似但意圖不同(Composite vs Decorator vs Proxy)。GoF 那張 Figure 1.1 模式關係圖,就是在說「這是一張網,不是 23 張獨立卡片」。
4. 為什麼「命名」本身就是貢獻
這點值得單獨講。在 GoF 之前,這些設計招式很多人都在用,但沒有共同名字——你只能在白板上畫半天、講十分鐘,對方才懂你想幹嘛。GoF 做的事,是把「這招」命名為 Observer、「那招」命名為 Strategy。從此兩個工程師可以直接說「這裡上一個 Observer」,溝通成本瞬間降到一個詞。這就是書裡說的 common design vocabulary(共同設計詞彙)——把設計討論從「程式碼層級」拉高到「模式層級」。
注意事項
⚠️ 這是 1994 年的書,背景是 C++ 和 Smalltalk,別當聖經教條套。 全書範例不是 C++ 就是 Smalltalk,很多「實作要點」是在補當年語言的不足。最重要的提醒先在這集講白:有些模式之所以存在,是因為當年的語言做不到某件事——一旦語言進步了(first-class function、reflection、現代泛型),那個模式可能就「消失」或「內建」了。後面每碰到一個,我會點一次。
⚠️ 別把「四要素」裡的 Consequences 跳過。 很多人讀 GoF 只看 Intent 和結構圖就以為懂了,結果到處亂套,這就是所謂的 patternitis(模式炎/模式中毒)——明明一個簡單 if 就解決,硬要上三層抽象。GoF 自己在導論結尾就警告:模式靠「增加一層間接」換彈性,這會讓設計更複雜、可能犧牲效能,只有真的需要那個彈性時才用。 這句話要在第一集就釘死。
專家補充
💡 「找出變與不變」這條,其實是整本書的『一句話總結』。 如果聽眾這季只能記住一件事,就是這個。23 個模式各自封裝了不同的「變化軸」:Abstract Factory 封裝「產品家族會變」、Strategy 封裝「演算法會變」、Decorator 封裝「職責組合會變」、Bridge 封裝「抽象和實作各自會變」。先把這個鏡頭給聽眾,後面每集都能用它快速定位「這個模式在封裝什麼」。
💡 Design Patterns 和 Refactoring 是『雙生兄弟』。 Martin Fowler 的《Refactoring》後來甚至出了《Refactoring to Patterns》,明講「模式是重構的目標」。GoF 自己在結語也說:模式捕捉的,正是物件導向軟體在「consolidating 階段」重構後會浮現的結構。所以這兩本書講的是同一件事的兩端——一個說「該長成什麼樣」,一個說「怎麼一步步長過去」。
💡 GoF 後來自己反省過 Singleton。 訪談裡幾位作者承認,如果重寫,會把 Singleton 拿掉——它太常被濫用成「包裝過的全域變數」。這個料先埋著,到 EP4 講創建型時引爆,會很有戲。
討論問題
🎙️ 開場鉤子:「你一定看過這種 code review——有人說『這裡用個 Strategy 吧』,全場點頭。但你有沒有想過,為什麼一個英文單字,就能讓一群工程師瞬間達成共識?這就是今天這本書幹的事。」
🎙️ 自問自答:「模式這麼多,到底先學原則還是先背模式?」——我的答案很明確:先吃原則。背得出 23 個模式但不懂「封裝變化」,你只會到處硬套;懂了三條原則,就算記不全模式,你也能自己長出對的設計。
🎙️ 帶走的一題:「打開你手上的專案,找一段你覺得『以後一定會改』的程式碼——那一塊,就是某個模式想幫你封裝的『變化』。先別急著套模式,先問自己:這裡會變的到底是什麼?」
更大範圍關聯
- 在軟體工程版圖中的座標:GoF 是「物件導向設計」這條支脈的奠基經典,和《Clean Code》《Refactoring》《A Philosophy of Software Design》同屬「怎麼把程式寫好」的工藝層。詳見 [軟體工程領域切分藍圖],本書落在 coding-practice/設計模式這格的源頭。
- 思想源頭——Christopher Alexander:GoF 的「pattern」概念整個借自建築師 Alexander 的《A Pattern Language》。Alexander 談的是城市與建築的反覆結構,GoF 把它移植到軟體。這條淵源到 EP11 結語會正式登場。
- 與 Refactoring 的關係:Fowler《Refactoring》+《Refactoring to Patterns》是 GoF 的「動詞版」——GoF 講靜態結構,Fowler 講怎麼演化過去。
- 入門替身:覺得 GoF 太硬的人,市場上有《Head First Design Patterns》用大量圖解和 Java 重講同一批模式,是很好的「先讀它再回來啃 GoF」的橋樑。
- 對立/補充觀點預告:John Ousterhout《A Philosophy of Software Design》會質疑「為了套模式而增加層數」;而 functional 陣營(如《Functional Design》)會主張很多 GoF 模式在 FP 裡根本不需要存在——這兩條伏筆貫穿整季。
錄製建議
- 建議時長:約 22-25 分鐘。配比:什麼是模式+四要素約 8 分、三條核心原則約 10 分(這是主菜,慢慢講)、分類與命名的價值約 5 分、注意事項收尾約 3 分。
- 討論策略:開場用「一個單字達成共識」的 code review 場景最有共鳴。中段三條原則建議用「反例先行」——先演一段爛 code(到處 new 具體類別、繼承爆炸),再說「GoF 怎麼救」。結尾務必把「模式是手段、原則是目的」和「別得 patternitis」這兩條釘死,這是整季的定調。
- 這是系列起手集,記得花 30-60 秒介紹 GoF 是誰、這 23 個模式怎麼分三類、整季大概怎麼走,建立系列地圖感。