把一族「可以互換的演算法」各自封裝成獨立物件,讓使用端在執行期挑一個用。核心是把「會變的那一步」抽成介面,用組合注入,而不是寫死成 if-else。
🧠 When to Use
TIP
訊號:同一件事有很多種「做法」要在執行期切換(排序規則、計費方式、壓縮演算法、付款管道),而且你正想寫一個大 when。
- 一個行為有多種變體,要依情境 / 設定 / 使用者選擇切換。
- 想消除依型別分支的
if/else、switch,改用多型。 - 演算法本身會獨立演化,想各自測試、各自替換。
⚖️ Structure & Variants
經典版 — 介面 + 多個實作,組合注入
fun interface PricingStrategy { fun price(base: Int): Int }
val regular = PricingStrategy { it }
val member = PricingStrategy { (it * 0.9).toInt() }
val vip = PricingStrategy { (it * 0.8).toInt() }
class Checkout(private val pricing: PricingStrategy) { // ← 注入策略
fun total(base: Int) = pricing.price(base)
}
Checkout(vip).total(1000) // 800Checkout不知道有幾種定價、也不含任何if;換策略 = 換注入物件。
函數式版 — 策略就是一個函數
- 當策略沒有狀態,介面只有一個方法時,直接傳一個 lambda / function 就是策略模式(如上
fun interface)。 - 這也是為什麼在 FP 裡「策略模式」幾乎隱形——高階函數本來就在做這件事。
和 State 的差別(結構幾乎一樣)
- Strategy:由外部選定一個演算法,物件存活期內通常不自己換。
- State:狀態物件自己決定下一個狀態,行為隨內部狀態流轉而改變。
- 結構同形,差在「誰決定切換、切換語意是不是狀態機」。
⚠️ Misuse & Anti-patterns
- 只有一種策略:沒有第二個實作、未來也不會有,抽介面只是憑空多一層。先 YAGNI。
- 策略間其實共用大量程式:硬拆成平行類別會造成重複;考慮 Template Method 或把共用部分上提。
- 用工廠把 switch 搬家而非消滅:如果選策略的地方還是一個巨大的
when(type),只是把味道從 A 處搬到 B 處——把對應關係改成查表 / 註冊表才算真的解掉。
🔑 Takeaways
- 本質是「把會變的演算法抽成介面、用組合注入」,是組合優於繼承最典型的落地。
- 單方法、無狀態的策略,直接用 lambda 就好,不必開一堆類別。
- 和 State 同構,靠「誰決定切換」區分;別把選策略的大 switch 只是搬家而沒消滅。
No notes yet — jot your takeaways or Q&A here.