策略模式(Strategy Pattern)是一種行為設計模式,其核心思想是將算法的定義與使用分離,使算法可以獨立于客戶端進行變化。它通過定義一系列算法,將每個算法封裝到獨立的類中,并使它們可以互相替換,從而讓算法的變化不會影響到使用算法的客戶端。
介紹
策略模式的核心組件
-
策略接口(Strategy Interface):
定義所有具體策略必須實現的公共方法,通常是一個抽象類或接口。例如,在排序場景中,策略接口可能定義sort()
方法。 -
具體策略(Concrete Strategies):
實現策略接口的具體算法類。例如:BubbleSort
、QuickSort
、MergeSort
等。 -
上下文(Context):
持有一個策略接口的引用,負責根據需要動態切換具體策略。上下文不直接實現算法,而是將工作委托給策略對象。 -
客戶端(Client):
負責創建具體策略并將其注入到上下文中,控制策略的選擇邏輯。
策略模式的特點
-
可替換性:
客戶端可以在運行時動態切換策略,無需修改上下文代碼。 -
開閉原則:
新增策略只需實現接口,無需修改現有代碼,符合“對擴展開放,對修改關閉”的原則。 -
解耦算法:
算法的實現細節被封裝在具體策略中,客戶端無需關心其內部邏輯。 -
消除條件語句:
避免使用大量if-else
或switch
語句來選擇算法,使代碼更簡潔。
適用場景
- 多種算法選擇:當一個問題有多種解決算法,且需要在運行時動態切換時。
- 避免條件語句:替代大量的
if-else
或switch
語句,使代碼更清晰。 - 算法封裝:將算法的實現細節與使用算法的客戶端代碼分離。
實現
#include <iostream>
#include <memory>
#include <string>// 策略接口:定義算法族
class SortStrategy {
public:virtual ~SortStrategy() = default;virtual void sort(std::vector<int>& data) const = 0;
};// 具體策略:冒泡排序
class BubbleSort : public SortStrategy {
public:void sort(std::vector<int>& data) const override {std::cout << "使用冒泡排序..." << std::endl;// 冒泡排序實現int n = data.size();for (int i = 0; i < n - 1; ++i) {for (int j = 0; j < n - i - 1; ++j) {if (data[j] > data[j + 1]) {std::swap(data[j], data[j + 1]);}}}}
};// 具體策略:快速排序
class QuickSort : public SortStrategy {
public:void sort(std::vector<int>& data) const override {std::cout << "使用快速排序..." << std::endl;// 快速排序實現quickSort(data, 0, data.size() - 1);}private:void quickSort(std::vector<int>& data, int left, int right) const {if (left < right) {int pivotIndex = partition(data, left, right);quickSort(data, left, pivotIndex - 1);quickSort(data, pivotIndex + 1, right);}}int partition(std::vector<int>& data, int left, int right) const {int pivot = data[right];int i = left - 1;for (int j = left; j < right; ++j) {if (data[j] <= pivot) {++i;std::swap(data[i], data[j]);}}std::swap(data[i + 1], data[right]);return i + 1;}
};// 上下文:維護一個策略引用
class Sorter {
private:std::unique_ptr<SortStrategy> strategy;public:explicit Sorter(std::unique_ptr<SortStrategy> strategy): strategy(std::move(strategy)) {}void setStrategy(std::unique_ptr<SortStrategy> strategy) {this->strategy = std::move(strategy);}void performSort(std::vector<int>& data) const {if (strategy) {strategy->sort(data);} else {std::cout << "未設置排序策略" << std::endl;}}
};// 客戶端代碼
int main() {std::vector<int> data = {5, 4, 3, 2, 1};// 使用冒泡排序Sorter sorter(std::make_unique<BubbleSort>());sorter.performSort(data);for (int num : data) {std::cout << num << " ";}std::cout << std::endl;// 切換為快速排序data = {5, 4, 3, 2, 1};sorter.setStrategy(std::make_unique<QuickSort>());sorter.performSort(data);for (int num : data) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
應用場景
- 排序算法切換:根據數據規模選擇冒泡排序、快速排序等。
- 支付方式:電商系統中支持支付寶、微信、銀行卡等多種支付方式。
- 壓縮算法:文件壓縮工具支持ZIP、RAR、7Z等不同壓縮算法。
- 游戲AI:不同難度的敵人使用不同的行為策略。
- 加密算法:安全系統中動態選擇加密方式(MD5、SHA-256等)。
策略模式與其他模式的對比
模式 | 核心區別 |
---|---|
策略模式 | 算法的定義與使用分離,強調運行時動態切換。 |
狀態模式 | 行為隨內部狀態變化而變化,狀態轉換通常由上下文觸發。 |
工廠模式 | 專注于對象的創建,而不涉及對象的行為。 |
策略模式優化(注冊機制和反射)
優化措施
-
策略工廠與注冊機制:
StrategyFactory
使用單例模式管理策略的創建- 通過
registerStrategy
方法注冊策略名稱和對應的工廠函數 StrategyRegistrar
模板類用于靜態注冊,避免手動調用注冊函數
-
反射機制:
- 使用
std::function
和 lambda 表達式實現類型擦除 - 通過字符串名稱動態創建策略對象
- 靜態注冊確保在程序初始化時完成所有策略的注冊
- 使用
-
Sorter類改進:
- 在構造函數中初始化所有策略實例
- 使用
std::unordered_map
管理策略對象 - 通過
setStrategy
方法動態切換當前使用的策略 - 所有策略對象僅創建一次,提高性能
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <unordered_map>
#include <functional>// 策略接口
class SortStrategy {
public:virtual ~SortStrategy() = default;virtual void sort(std::vector<int>& data) const = 0;
};// 具體策略:冒泡排序
class BubbleSort : public SortStrategy {
public:void sort(std::vector<int>& data) const override {std::cout << "使用冒泡排序..." << std::endl;int n = data.size();for (int i = 0; i < n - 1; ++i) {for (int j = 0; j < n - i - 1; ++j) {if (data[j] > data[j + 1]) {std::swap(data[j], data[j + 1]);}}}}
};// 具體策略:快速排序
class QuickSort : public SortStrategy {
public:void sort(std::vector<int>& data) const override {std::cout << "使用快速排序..." << std::endl;quickSort(data, 0, data.size() - 1);}private:void quickSort(std::vector<int>& data, int left, int right) const {if (left < right) {int pivotIndex = partition(data, left, right);quickSort(data, left, pivotIndex - 1);quickSort(data, pivotIndex + 1, right);}}int partition(std::vector<int>& data, int left, int right) const {int pivot = data[right];int i = left - 1;for (int j = left; j < right; ++j) {if (data[j] <= pivot) {++i;std::swap(data[i], data[j]);}}std::swap(data[i + 1], data[right]);return i + 1;}
};// 策略工廠:負責創建策略實例
class StrategyFactory {
public:static StrategyFactory& getInstance() {static StrategyFactory instance;return instance;}void registerStrategy(const std::string& name, std::function<std::unique_ptr<SortStrategy>()> factory) {factories[name] = factory;}std::unique_ptr<SortStrategy> createStrategy(const std::string& name) {auto it = factories.find(name);if (it != factories.end()) {return it->second();}return nullptr;}private:StrategyFactory() = default;std::unordered_map<std::string, std::function<std::unique_ptr<SortStrategy>()>> factories;
};// 策略注冊表:靜態注冊策略
template<typename T>
struct StrategyRegistrar {StrategyRegistrar(const std::string& name) {StrategyFactory::getInstance().registerStrategy(name, []() {return std::make_unique<T>();});}
};// 上下文:維護策略并提供排序功能
class Sorter {
public:Sorter() {strategies["bubble"] = StrategyFactory::getInstance().createStrategy("bubble");strategies["quick"] = StrategyFactory::getInstance().createStrategy("quick");currentStrategy = strategies["bubble"].get();}void setStrategy(const std::string& name) {auto it = strategies.find(name);if (it != strategies.end()) {currentStrategy = it->second.get();} else {std::cout << "未找到策略: " << name << std::endl;}}void performSort(std::vector<int>& data) const {if (currentStrategy) {currentStrategy->sort(data);} else {std::cout << "未設置排序策略" << std::endl;}}private:std::unordered_map<std::string, std::unique_ptr<SortStrategy>> strategies;SortStrategy* currentStrategy;
};// 靜態注冊策略
static StrategyRegistrar<BubbleSort> bubbleRegistrar("bubble");
static StrategyRegistrar<QuickSort> quickRegistrar("quick");// 客戶端代碼
int main() {std::vector<int> data = {5, 4, 3, 2, 1};Sorter sorter;// 使用冒泡排序sorter.setStrategy("bubble");sorter.performSort(data);for (int num : data) {std::cout << num << " ";}std::cout << std::endl;// 切換為快速排序data = {5, 4, 3, 2, 1};sorter.setStrategy("quick");sorter.performSort(data);for (int num : data) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
添加新策略時,只需:
- 創建新的策略類,繼承自
SortStrategy
- 實現
sort
方法 - 添加靜態注冊語句:
static StrategyRegistrar<NewSortStrategy> newRegistrar("new");
// 無需修改 Sorter
類,完全符合開閉原則。
客戶端通過字符串名稱即可使用新策略,實現了對修改封閉,對擴展開放的設計目標。