
如果你的 code 裡有一坨 if-else 或 switch 在決定「這次要用哪種算法」,那你其實已經在做 Strategy Pattern 了——只是做得很醜而已。
先講結論
Strategy Pattern 的精髓是:把會變的行為抽出去,讓它可以被替換。Context 不管你用哪種策略,它只管呼叫 execute()。新增策略?寫一個新 class 就好,舊的完全不用動。
classDiagram class Context { -strategy : Strategy +setStrategy(strategy) void +executeStrategy() any } class Strategy { <<interface>> +execute()* any } class ConcreteStrategyA { +execute() any } class ConcreteStrategyB { +execute() any } Context --> Strategy Strategy <|.. ConcreteStrategyA Strategy <|.. ConcreteStrategyB
實戰:電商折扣系統
雙十一打八折、黑五打七折、會員日九折——你打算全寫在同一個 calculateDiscount 裡嗎?
// 策略們
class BlackFridayStrategy {
applyDiscount(amount) {
return amount * 0.7; // 七折
}
}
class MemberDayStrategy {
applyDiscount(amount) {
return amount * 0.9; // 九折
}
}
class NoDiscountStrategy {
applyDiscount(amount) {
return amount; // 原價,殘忍
}
}
// Context
class PromotionContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
calculateDiscount(amount) {
return this.strategy.applyDiscount(amount);
}
}
// 使用
const context = new PromotionContext(new BlackFridayStrategy());
console.log(context.calculateDiscount(1000)); // 700
// 活動結束,切回原價
context.setStrategy(new NoDiscountStrategy());
console.log(context.calculateDiscount(1000)); // 1000重點在於:加一個「春節特賣策略」?寫一個新 class 就好。PromotionContext 一行都不用改。
Strategy vs 一堆 if-else
| 做法 | 新增策略時 | 可讀性 | 測試難度 |
|---|---|---|---|
| if-else | 改原本的 function | 越來越長 | 整坨一起測 |
| Strategy | 新增一個 class | 每個策略獨立 | 各自測各自的 |
跟 State Pattern 有什麼不同?
好問題。結構幾乎一樣,但意圖不同:
- Strategy:你主動選擇要用哪個策略(「我要用黑五折扣」)
- State:狀態自己決定下一步(「訂單從 pending 變成 processing」)
如果策略是由外部決定的,用 Strategy;如果行為隨內部狀態自動變化,用 State。
小心過度設計
如果你只有兩種策略,而且未來也不太會增加——一個 if-else 就夠了,不需要硬套 pattern。設計模式是解決問題的,不是拿來寫在履歷上的。
Strategy Pattern 就像手機換殼——手機功能不變,但你可以隨心情換個外觀。只不過,如果你只有一個殼,那你其實不需要一個殼的收納架。
延伸閱讀
- Observer 模式 — 同屬行為型模式
- State 模式 — 與 Strategy 結構相似
- Factory 模式 — 可搭配工廠模式動態建立策略
- Command 模式 — 將行為封裝成物件