🐦 Head First 設計模式
學原則 > 背 23 個模式
🎯 什麼情境該想到我
當某部分需求「經常改」、每次一改就要動很多地方,想把變化隔離起來時。這是所有設計模式的共同本質。
⚙️ 怎麼用
- 找出「會變」與「不變」的部分:把兩者分開。
- 把會變的部分抽成獨立元件(介面 + 可替換實作),讓不變的部分依賴抽象。
- 未來需求變動只需新增/替換那個元件,不動其餘(呼應 工具-開閉原則)。
例:付款方式會變 → 抽出 PaymentMethod 介面,新增付款方式=加一個實作。
🧪 我實際套用的紀錄
- 2026-07-14:(待填)
⚠️ 注意
- 只封裝「真的會變」的點;對不會變的東西加彈性=過度設計、徒增複雜度。
🔗 相關工具
- 工具-針對介面編程 —— 封裝變化的落地方式,把會變的部分藏到介面後面
- 工具-優先組合而非繼承 —— 組裝方式,用組合替換變化的部分比用繼承覆寫更好抽換
- 工具-管理複雜度 —— 上位準則,封裝變化本質上是在降低要同時記住的東西
找出會變的部分 把變動的部分抽離、封裝起來,讓其他不變的部分不受影響——所有模式的共同本質。
🎯 封裝變化(核心心法)
🎯 什麼情境該想到我
當你的程式碼「依賴具體類別」導致改一處動全身、難替換、難測試時。
⚙️ 怎麼用
- 依賴抽象(介面/父型別),不依賴具體實作:呼叫端只認介面。
- 物件的建立與使用分離:用工廠/注入取得具體實作,使用處不 new 具體類別。
- 好處:實作可自由替換(換套件、換演算法)、可在測試中換測試替身。
🧪 我實際套用的紀錄
- 2026-07-14:(待填)
⚠️ 注意
- 別為了「未來也許會變」而到處加介面;在確有變化點或需要測試隔離時才抽(見 工具-封裝變化點)。
🔗 相關工具
- 工具-優先組合而非繼承 —— 常一起用,組合進來的東西是介面,換實作才不牽動使用端
- 工具-封裝變化點 —— 目的,介面是把變化藏起來最常用的那道牆
- 工具-打破依賴以便測試 —— 驗收方式,能不能塞測試替身進去,就是介面抽對沒有的檢查
- 工具-介面設計原則 —— 品質要求,介面本身設計不好,抽象只是換個地方糾纏
🧩 組合與介面
鬆耦合 讓互動的物件之間所知越少越好(如 [[觀察者模式|Observer]]:主題只知道觀察者實作了某介面)。
最少知識原則(迪米特法則) 只和你的「密友」交談,別讓呼叫鏈穿透太多物件。
🔗 力求鬆耦合
🎯 什麼情境該想到我
當你「每加一個新功能/新類型,就得回頭改一堆既有程式(還常改壞)」,或 if-else/switch 越加越長時。
⚙️ 怎麼用
對擴充開放,對修改關閉:新增行為靠「加新程式」,而不是「改舊程式」。
- 找出會不斷新增類型/行為的變化點。
- 抽成介面,讓既有流程依賴介面(見 工具-針對介面編程)。
- 新增功能=新增一個實作類別,既有程式碼不動。
- 例:新增付款方式=加一個
PaymentMethod實作,不改結帳流程。
- 例:新增付款方式=加一個
🧪 我實際套用的紀錄
- 2026-07-14:(待填)
⚠️ 注意
- 不可能對「所有」變化都開放;只針對你判斷會反覆變的軸線設計(見 工具-封裝變化點),否則過度設計。
🔗 相關工具
- 工具-封裝變化點 —— 前置動作,先找出哪裡會變,才知道該對什麼開放擴充
- 工具-針對介面編程 —— 實作手段,靠介面把新舊實作隔開,加新的才不必改舊的
- 工具-好萊塢原則與依賴反轉 —— 架構層放大版,把依賴方向反轉過來,高層就不受低層變動影響
🎯 什麼情境該想到我
當高層業務邏輯直接依賴低層細節(DB、第三方),導致底層一改就害到上層,或你想做「可插拔」架構時。
⚙️ 怎麼用
- 依賴反轉(DIP):高層與低層都依賴抽象,別讓高層依賴具體低層。
- 好萊塢原則:「別打電話給我們,我們會打給你。」——由高層/框架決定何時呼叫低層元件,低層只實作被回呼的介面,不主動反向依賴高層。
- 效果:控制流與依賴方向解耦,低層變成可替換的外掛(框架、DI 容器都靠這個)。
🧪 我實際套用的紀錄
- 2026-07-14:(待填)
⚠️ 注意
- 抽象要放在「高層擁有、低層實作」的位置,別讓抽象反而綁死在低層。
🔗 相關工具
- 工具-針對介面編程 —— 依賴反轉的基本工具,抽象要先存在才有反轉可言
- 工具-開閉原則 —— 依賴反轉之後自然得到的效果:加新實作不必改高層邏輯
- 工具-打破依賴以便測試 —— 最實際的驗收方式:能不能單獨測試,就是依賴方向對不對的檢查器
🚪 擴充性與依賴方向
懂原則就能推導模式 原則是「為什麼」,模式是「怎麼做」;先懂原則,模式自然浮現。
完整 23 模式定義 更正式的型錄與分類見 [[設計模式]](GoF)。
📖 與 GoF 型錄的關係