一、基本概念
既然你已經接觸到了設計模式,那你大概率你寫過類似這樣的代碼:根據不同的選擇條件(如排序、搜索或路由)執行不同的代碼邏輯。通常的解決方案是使用if-else
或switch
語句,但這些條件判斷有一個最大的問題是不夠靈活,難以擴展(也就是違背了開閉原則)。
策略模式是一種行為型設計模式,策略模式提供了一種更優雅的解決方案,你可以定義一系列算法,然后將每個算法封裝成獨立類,使得無需修改核心邏輯就能在不同算法(代碼邏輯)間自由切換。
The algorithm can change without changing the context that uses it.
相比于將所有代碼邏輯硬編碼在一個龐大的類中,更好的方案是編寫不同的策略(算法),然后將它們靈活的插入上下文。
案例類比:去公司的交通方式。
假設你是一只每天可以睡到10點才去上班的哈基米,有以下交通方式可選:
? 共享單車:環保但費力
? 公交:便宜但不夠靈活(可能還要步行一段兒)
? 嘀嘀打車:唯一的缺點就是貴
這些都是交通策略(可以看做一個個獨立的算法)。根據時間、預算或心情,你可以選擇不同策略。決策邏輯不變,只是切換策略而已,這和策略模式在代碼中的使用方式比較相似。
2. 使用案例
2.1 情景引入
擴展剛才的案例,假設你跳槽了,換了一家公司,但你對公司所在位置不熟悉,正在學習軟件開發的你打算開發一個導航應用,支持多種出行方式的路線規劃。
- 步行路線
- 自行車路線
- 公交路線
- 駕車路線
在v1版本,你只實現了你最常用的公交路線。隨后陸續添加了步行、自行車和駕車等功能。最終你完成了這樣的路線計算方法:
if (mode.equals("bus")) {// 駕車路線代碼邏輯
} else if (mode.equals("walk")) {// 步行路線代碼邏輯
} else if (mode.equals("bike")) {// 自行車路線代碼邏輯
} else { // 其他模式...
}
隨著路線規劃方式的增加,if-else變得越來越多。如果你打算和朋友協作完成這個項目,你會發現代碼修改不方便,甚至合并時還會產生沖突。
2.2 解決方案——策略模式
2.2.1核心概念
- 策略接口:聲明算法規約(如execute()方法)。
- 具體策略:實現策略接口的不同算法。
- 上下文:持有策略引用并將行為委托給這個引用。
- 客戶端:選擇使用哪種策略并注入上下文。
2.2.2 Java實現
第一步:定義策略接口
public interface RouteStrategy {String execute();
}
第二步:實現具體策略
// 駕車路線策略
public class DriveStrategy implements RouteStrategy {@Overridepublic String execute() {return "Bike route";}
}// 步行路線策略
public class WalkStrategy implements RouteStrategy {@Overridepublic String execute() {return "Walk route";}
}// 公共交通路線策略
public class MassTransitStrategy implements RouteStrategy {@Overridepublic String execute() {return "MassTransit route";}
}
第三步:上下文類
public class Context {// 注入策略接口(持有引用)private RouteStrategy routeStrategy;public void setRouteStrategy(RouteStrategy routeStrategy) {this.routeStrategy = routeStrategy;}// 行為委托給這個引用public String getRoute() {if (routeStrategy == null) {throw new IllegalStateException("未設置策略!");}return routeStrategy.execute();}
}
第四步:客戶端選擇策略
public class Client {public static void main(String[] args) {Context context = new Context();context.setRouteStrategy(new DriveStrategy());System.out.println("駕車路線: " + context.getRoute());context.setRouteStrategy(new WalkStrategy());System.out.println("步行路線: " + context.getRoute());context.setRouteStrategy(new MassTransitStrategy());System.out.println("公共交通路線: " + context.getRoute());}
}
執行結果
3. 策略模式 vs 狀態模式
策略模式(Strategy) 和 狀態模式(State) 看起來很相似:二者都通過委托實現,替換一個實現了相同接口的不同對象。但它們在設計意圖、控制流和動機上存在本質區別。
策略模式 | 狀態模式 | |
---|---|---|
設計意圖 | 核心是讓客戶端(外部調用者)選擇具體算法,關注的是可獨立變化的行為。例如上述案例中選擇不同路徑計算邏輯。 | 用于表示一個對象在不同時間點的不同狀態或條件,其狀態轉換由對象自身的內在邏輯決定 |
控制流 | 客戶端顯式決定使用哪種策略(如通過 setStrategy(…) 動態切換) | 狀態轉換由上下文對象內部驅動,行為隨狀態自動改變,客戶端通常無需感知具體狀態。 |
感知與狀態轉換?? | 各策略對象之間??相互獨立??,彼此無感知。例如,快速排序策略無需知道冒泡排序的存在。 | 狀態對象通常??知曉其他狀態??,并能主動觸發轉換。例如,媒體播放器的 PlayingState(播放狀態)可自行切換到 PausedState(暫停狀態)。 |
使用場景 | 算法可能變化且應由客戶端選擇時 | 對象行為需要根據其生命周期演變時 |
4. 策略模式適用場景
在以下情況使用策略模式:
? 需要支持多種實現方式(算法)
? 需在運行時切換邏輯
? 希望遵循開閉原則
? 要避免if-else或switch語句膨脹
優缺點分析
優點
? 運行時切換算法
? 符合單一職責原則,代碼更清晰
? 添加新算法不影響核心邏輯
? 便于測試和擴展
缺點
? 需要創建更多類
? 客戶端必須了解策略選擇
? 對簡單任務可能過度設計
5. 總結
策略模式是管理算法變化的優雅方案。通過將行為委托給策略類,避免了if-else語句的混亂。