C++設計模式系列文章目錄
【第一篇】C++單例模式–懶漢與餓漢以及線程安全
【C++設計模式】第二篇:策略模式(Strategy)--從基本介紹,內部原理、應用場景、使用方法,常見問題和解決方案進行深度解析
- 一、策略模式的基本介紹
- 1.1 模式定義與核心思想
- 1.2 模式本質與設計原則
- 1.3 模式結構與角色
- 1.3.1 策略接口(Strategy)
- 1.3.2 具體策略類(Concrete Strategy)
- 1.3.3 上下文類(Context)
- 1.4 簡單使用示例
- 二、策略模式的內部原理
- 2.1 封裝與委托機制
- 2.2 多態的運用
- 2.3 策略的動態切換
- 2.4 策略的選擇與決策
- 2.4.1 客戶端直接選擇
- 2.4.2 配置文件或數據庫
- 2.4.3 工廠模式結合
- 三、策略模式的應用場景
- 3.1 典型應用場景
- 3.1.1 排序算法選擇
- 3.1.2 加密算法選擇
- 3.1.3 支付方式選擇
- 3.2 企業級應用案例
- 3.2.1 電商促銷活動
- 3.2.2 物流配送策略
- 3.3 模式適用條件
- 四、策略模式的使用方法
- 4.1 實現步驟詳解
- 4.1.1 定義策略接口
- 4.1.2 實現具體策略類
- 4.1.3 創建上下文類
- 4.1.4 使用策略模式
- 4.2 代碼實現技巧
- 4.2.1 使用智能指針管理策略對象
- 4.2.2 結合工廠模式創建策略對象
- 4.2.3 策略參數化
- 五、常見問題及解決方案
- 5.1 常見問題分析
- 5.1.1 策略類數量過多
- 5.1.2 客戶端需要了解所有策略類
- 5.1.3 策略類之間的依賴關系
- 5.1.4 策略的初始化和銷毀
- 5.2 解決方案
- 5.2.1 策略類的合并與分組
- 5.2.2 使用工廠模式或配置文件
- 5.2.3 依賴注入
- 5.2.4 資源管理類
- 六、總結
- 6.1 模式優點
- 6.2 模式缺點
- 6.3 最佳實踐建議
- 6.4 未來發展趨勢
原文鏈接:https://blog.csdn.net/qianniulaoren/article/details/146539044
原文鏈接:https://blog.csdn.net/weixin_45712636/article/details/124328504
C++設計模式(全23種)
一、策略模式的基本介紹
Strategy 模式和 Template 模式要解決的問題是相同(類似)的,都是為了給業務邏輯(算法)具體實現和抽象接口之間的解耦。
簡而言之,Strategy 模式是對算法的封裝。處理一個問題的時候可能有多種算法,這些算法的接口(輸入參數,輸出參數等)都是一致的,那么可以考慮采用Strategy 模式對這些算法進行封裝,在基類中定義一個函數接口就可以了。
舉例:
假如現在有個英雄需要使用武器對付敵人,武器有兩種匕首和AK,那么這么選擇使用哪吧武器其實就是一種策略了那么就可以將策略模式分為三部分:
Strategy 策略基類 (抽象武器)
ConcreteStrategy 具體策略 (使用匕首或AK)
Context 具體使用策略的對象(英雄)
代碼:
//策略模式
#include <iostream>
using namespace std;//抽象武器 策略基類(抽象的策略)
class WeaponStrategy {
public:virtual void UseWeapon() = 0;
};//具體的策略使用匕首作為武器
class Knife :public WeaponStrategy {
public:virtual void UseWeapon() {cout << "使用匕首" << endl;}
};//具體的策略使用AK47作為武器
class AK47 :public WeaponStrategy {
public:virtual void UseWeapon() {cout << "使用AK47" << endl;}
};//具體使用策略的角色
class Character {
public:WeaponStrategy* pWeapon;void setWeapon(WeaponStrategy* pWeapon) {this->pWeapon = pWeapon;}void ThrowWeapon() {this->pWeapon->UseWeapon();}
};void test01() {Character* character = new Character;WeaponStrategy* knife = new Knife;WeaponStrategy* ak47 = new AK47;//用匕首當作武器character->setWeapon(knife);character->ThrowWeapon();character->setWeapon(ak47);character->ThrowWeapon();delete ak47;delete knife;delete character;
}int main()
{test01();
}
1.1 模式定義與核心思想
策略模式(Strategy Pattern)是一種行為型設計模式,它定義了一系列的算法,并將每個算法封裝起來,使它們可以相互替換。策略模式讓算法的變化獨立于使用算法的客戶端。
簡單來說,就是我們有多種解決問題的方法(算法),把這些方法分別封裝好,然后在需要的時候可以靈活地選擇使用哪一種方法,而不用改變使用這些方法的代碼。這就好比我們出行可以選擇步行、騎自行車、坐公交車或者打車,不同的出行方式就是不同的策略,我們可以根據實際情況(比如距離遠近、時間充裕與否等)來選擇合適的策略。
1.2 模式本質與設計原則
策略模式的本質是將算法的定義和使用分離。它遵循了開閉原則(Open - Closed Principle),即對擴展開放,對修改關閉。當我們需要新增一種算法時,只需要創建一個新的策略類,而不需要修改使用這些算法的客戶端代碼。同時,它也遵循了單一職責原則,每個策略類只負責實現一種具體的算法,職責清晰。
1.3 模式結構與角色
策略模式主要包含以下三個角色:
1.3.1 策略接口(Strategy)
策略接口定義了所有具體策略類必須實現的方法。它是所有具體策略的公共抽象,客戶端通過這個接口來調用具體策略的算法。
// 策略接口
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() {}
};
1.3.2 具體策略類(Concrete Strategy)
具體策略類實現了策略接口中定義的方法,每個具體策略類封裝了一種具體的算法。
// 具體策略類A
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout << "Executing strategy A" << std::endl;}
};// 具體策略類B
class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout << "Executing strategy B" << std::endl;}
};
1.3.3 上下文類(Context)
上下文類持有一個策略接口的引用,負責根據客戶端的需求選擇合適的策略,并調用該策略的方法。
// 上下文類
class Context {
private:Strategy* strategy;
public:Context(Strategy* s) : strategy(s) {}void setStrategy(Strategy* s) {strategy = s;}void executeStrategy() {if (strategy) {strategy->execute();}}
};
1.4 簡單使用示例
下面是一個簡單的使用策略模式的示例代碼:
#include <iostream>// 策略接口
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() {}
};// 具體策略類A
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout << "Executing strategy A" << std::endl;}
};// 具體策略類B
class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout << "Executing strategy B" << std::endl;}
};// 上下文類
class Context {
private:Strategy* strategy;
public:Context(Strategy* s) : strategy(s) {}void setStrategy(Strategy* s) {strategy = s;}void executeStrategy() {if (strategy) {strategy->execute();}}
};int main() {ConcreteStrategyA strategyA;ConcreteStrategyB strategyB;Context context(&strategyA);context.executeStrategy();context.setStrategy(&strategyB);context.executeStrategy();return 0;
}
在這個示例中,我們首先定義了策略接口 Strategy,然后實現了兩個具體策略類 ConcreteStrategyA 和 ConcreteStrategyB。接著創建了上下文類 Context,它持有一個 Strategy 指針。在 main 函數中,我們先創建了兩個具體策略的對象,然后將 ConcreteStrategyA 傳遞給 Context 對象,調用 executeStrategy 方法執行策略 A。之后,我們通過 setStrategy 方法將策略切換為 ConcreteStrategyB,再次調用 executeStrategy 方法執行策略 B。
二、策略模式的內部原理
2.1 封裝與委托機制
策略模式的核心在于封裝和委托。封裝體現在每個具體策略類將自己的算法實現封裝在內部,對外只提供一個統一的接口。這樣,客戶端不需要關心具體策略的實現細節,只需要通過策略接口來調用相應的方法。
委托機制則體現在上下文類中。上下文類持有一個策略接口的引用,它將具體的算法執行委托給了具體的策略類。當客戶端調用上下文類的 executeStrategy 方法時,上下文類只是簡單地調用其所持有的策略對象的 execute 方法,從而實現了算法的執行。
2.2 多態的運用
策略模式充分利用了 C++ 的多態特性。策略接口定義了一個純虛函數 execute,具體策略類通過重寫這個函數來實現自己的算法。上下文類持有一個策略接口的指針,當調用 executeStrategy 方法時,根據指針實際指向的具體策略類對象,會調用相應的 execute 方法,這就是多態的體現。
例如,在上面的示例中,Context 類中的 executeStrategy 方法:
void executeStrategy() {if (strategy) {strategy->execute();}
}
這里的 strategy 指針可以指向 ConcreteStrategyA 或 ConcreteStrategyB 對象,當調用 strategy->execute() 時,會根據 strategy 實際指向的對象調用相應的 execute 方法,從而實現了不同策略的動態切換。
2.3 策略的動態切換
策略模式允許在運行時動態地切換策略。上下文類提供了 setStrategy 方法,通過調用這個方法,我們可以在程序運行過程中隨時更換所使用的策略。
例如:
int main() {ConcreteStrategyA strategyA;ConcreteStrategyB strategyB;Context context(&strategyA);context.executeStrategy();context.setStrategy(&strategyB);context.executeStrategy();return 0;
}
在這個 main 函數中,我們先使用 ConcreteStrategyA 作為策略,然后通過 setStrategy 方法將策略切換為 ConcreteStrategyB,實現了策略的動態切換。
2.4 策略的選擇與決策
在實際應用中,如何選擇合適的策略是一個重要的問題。通常有以下幾種方式:
2.4.1 客戶端直接選擇
客戶端根據具體的業務需求,直接選擇合適的策略并傳遞給上下文類。例如:
if (conditionA) {context.setStrategy(new ConcreteStrategyA());
} else if (conditionB) {context.setStrategy(new ConcreteStrategyB());
}
2.4.2 配置文件或數據庫
可以將策略的選擇信息存儲在配置文件或數據庫中,程序在運行時讀取這些信息來選擇合適的策略。例如,配置文件中可能有一個字段表示當前使用的策略名稱,程序根據這個名稱來創建相應的策略對象。
2.4.3 工廠模式結合
使用工廠模式來創建策略對象。工廠類根據一定的規則(如輸入參數、配置信息等)來創建合適的策略對象,然后將其傳遞給上下文類。
class StrategyFactory {
public:static Strategy* createStrategy(const std::string& strategyName) {if (strategyName == "A") {return new ConcreteStrategyA();} else if (strategyName == "B") {return new ConcreteStrategyB();}return nullptr;}
};// 使用工廠創建策略
Strategy* strategy = StrategyFactory::createStrategy("A");
Context context(strategy);
三、策略模式的應用場景
3.1 典型應用場景
3.1.1 排序算法選擇
在排序算法中,我們可能有多種排序算法可供選擇,如冒泡排序、快速排序、歸并排序等。不同的排序算法在不同的場景下有不同的性能表現。我們可以使用策略模式將每種排序算法封裝成一個具體策略類,然后根據數據的特點(如數據量大小、數據的初始順序等)選擇合適的排序算法。
#include <iostream>
#include <vector>// 策略接口:排序策略
class SortStrategy {
public:virtual void sort(std::vector<int>& data) = 0;virtual ~SortStrategy() {}
};// 冒泡排序策略
class BubbleSort : public SortStrategy {
public:void sort(std::vector<int>& data) override {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 {
private:int partition(std::vector<int>& data, int low, int high) {int pivot = data[high];int i = low - 1;for (int j = low; j < high; ++j) {if (data[j] < pivot) {++i;std::swap(data[i], data[j]);}}std::swap(data[i + 1], data[high]);return i + 1;}void quickSort(std::vector<int>& data, int low, int high) {if (low < high) {int pi = partition(data, low, high);quickSort(data, low, pi - 1);quickSort(data, pi + 1, high);}}
public:void sort(std::vector<int>& data) override {quickSort(data, 0, data.size() - 1);}
};// 上下文類:排序上下文
class SortContext {
private:SortStrategy* strategy;
public:SortContext(SortStrategy* s) : strategy(s) {}void setStrategy(SortStrategy* s) {strategy = s;}void performSort(std::vector<int>& data) {if (strategy) {strategy->sort(data);}}
};int main() {std::vector<int> data = {5, 3, 8, 4, 2};BubbleSort bubbleSort;QuickSort quickSort;SortContext context(&bubbleSort);context.performSort(data);for (int num : data) {std::cout << num << " ";}std::cout << std::endl;data = {5, 3, 8, 4, 2};context.setStrategy(&quickSort);context.performSort(data);for (int num : data) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
3.1.2 加密算法選擇
在數據加密領域,有多種加密算法,如 AES、DES、RSA 等。不同的加密算法有不同的特點和適用場景。我們可以使用策略模式將每種加密算法封裝成一個具體策略類,然后根據數據的安全性要求、性能要求等選擇合適的加密算法。
3.1.3 支付方式選擇
在電商系統中,用戶可以選擇多種支付方式,如支付寶、微信支付、銀行卡支付等。每種支付方式的處理邏輯不同,我們可以使用策略模式將每種支付方式的處理邏輯封裝成一個具體策略類,然后根據用戶的選擇調用相應的支付策略。
3.2 企業級應用案例
3.2.1 電商促銷活動
在電商系統中,經常會有各種促銷活動,如滿減、折扣、贈品等。每種促銷活動的計算規則不同,我們可以使用策略模式將每種促銷活動的計算規則封裝成一個具體策略類。當用戶結算購物車時,根據當前的促銷活動選擇合適的策略來計算最終的價格。
#include <iostream>
#include <vector>// 商品類
class Product {
public:std::string name;double price;Product(const std::string& n, double p) : name(n), price(p) {}
};// 促銷策略接口
class PromotionStrategy {
public:virtual double calculateDiscount(const std::vector<Product>& products) = 0;virtual ~PromotionStrategy() {}
};// 滿減策略
class FullReductionStrategy : public PromotionStrategy {
private:double fullAmount;double reductionAmount;
public:FullReductionStrategy(double full, double reduction) : fullAmount(full), reductionAmount(reduction) {}double calculateDiscount(const std::vector<Product>& products) override {double total = 0;for (const auto& product : products) {total += product.price;}if (total >= fullAmount) {return reductionAmount;}return 0;}
};// 折扣策略
class DiscountStrategy : public PromotionStrategy {
private:double discountRate;
public:DiscountStrategy(double rate) : discountRate(rate) {}double calculateDiscount(const std::vector<Product>& products) override {double total = 0;for (const auto& product : products) {total += product.price;}return total * (1 - discountRate);}
};// 上下文類:購物車上下文
class ShoppingCartContext {
private:PromotionStrategy* strategy;std::vector<Product> products;
public:ShoppingCartContext(PromotionStrategy* s) : strategy(s) {}void setStrategy(PromotionStrategy* s) {strategy = s;}void addProduct(const Product& product) {products.push_back(product);}double calculateFinalPrice() {double total = 0;for (const auto& product : products) {total += product.price;}if (strategy) {double discount = strategy->calculateDiscount(products);total -= discount;}return total;}
};int main() {Product p1("Apple", 5.0);Product p2("Banana", 3.0);Product p3("Orange", 4.0);FullReductionStrategy fullReduction(10, 2);DiscountStrategy discount(0.8);ShoppingCartContext cart(&fullReduction);cart.addProduct(p1);cart.addProduct(p2);cart.addProduct(p3);std::cout << "Final price with full reduction: " << cart.calculateFinalPrice() << std::endl;cart.setStrategy(&discount);std::cout << "Final price with discount: " << cart.calculateFinalPrice() << std::endl;return 0;
}
3.2.2 物流配送策略
在物流系統中,有多種配送方式,如快遞、平郵、同城配送等。每種配送方式的收費規則、配送時間等不同,我們可以使用策略模式將每種配送方式的處理邏輯封裝成一個具體策略類,根據商品的重量、體積、目的地等信息選擇合適的配送策略。
3.3 模式適用條件
當系統滿足以下條件時,適合使用策略模式:
系統中有多種算法可以完成同一個任務,并且需要在運行時動態地選擇合適的算法。
算法的使用和算法的實現需要分離,以提高代碼的可維護性和可擴展性。
避免使用大量的條件語句來選擇不同的算法,使代碼更加清晰和易于理解。
四、策略模式的使用方法
4.1 實現步驟詳解
4.1.1 定義策略接口
首先,我們需要定義一個策略接口,該接口定義了所有具體策略類必須實現的方法。
// 策略接口
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() {}
};
4.1.2 實現具體策略類
根據策略接口,實現具體的策略類,每個具體策略類封裝了一種具體的算法。
// 具體策略類A
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout << "Executing strategy A" << std::endl;}
};// 具體策略類B
class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout << "Executing strategy B" << std::endl;}
};
4.1.3 創建上下文類
創建上下文類,該類持有一個策略接口的引用,負責根據客戶端的需求選擇合適的策略,并調用該策略的方法。
// 上下文類
class Context {
private:Strategy* strategy;
public:Context(Strategy* s) : strategy(s) {}void setStrategy(Strategy* s) {strategy = s;}void executeStrategy() {if (strategy) {strategy->execute();}}
};
4.1.4 使用策略模式
在客戶端代碼中,創建具體策略對象和上下文對象,選擇合適的策略并調用上下文對象的方法來執行策略。
int main() {ConcreteStrategyA strategyA;ConcreteStrategyB strategyB;Context context(&strategyA);context.executeStrategy();context.setStrategy(&strategyB);context.executeStrategy();return 0;
}
4.2 代碼實現技巧
4.2.1 使用智能指針管理策略對象
為了避免內存泄漏,我們可以使用智能指針(如 std::unique_ptr 或 std::shared_ptr)來管理策略對象。
#include <iostream>
#include <memory>// 策略接口
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() {}
};// 具體策略類A
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout << "Executing strategy A" << std::endl;}
};// 具體策略類B
class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout << "Executing strategy B" << std::endl;}
};// 上下文類
class Context {
private:std::unique_ptr<Strategy> strategy;
public:Context(std::unique_ptr<Strategy> s) : strategy(std::move(s)) {}void setStrategy(std::unique_ptr<Strategy> s) {strategy = std::move(s);}void executeStrategy() {if (strategy) {strategy->execute();}}
};int main() {auto strategyA = std::make_unique<ConcreteStrategyA>();auto strategyB = std::make_unique<ConcreteStrategyB>();Context context(std::move(strategyA));context.executeStrategy();context.setStrategy(std::move(strategyB));context.executeStrategy();return 0;
}
4.2.2 結合工廠模式創建策略對象
如前面提到的,使用工廠模式可以更方便地創建策略對象。
#include <iostream>
#include <memory>// 策略接口
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() {}
};// 具體策略類A
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout << "Executing strategy A" << std::endl;}
};// 具體策略類B
class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout << "Executing strategy B" << std::endl;}
};// 策略工廠類
class StrategyFactory {
public:static std::unique_ptr<Strategy> createStrategy(const std::string& strategyName) {if (strategyName == "A") {return std::make_unique<ConcreteStrategyA>();} else if (strategyName == "B") {return std::make_unique<ConcreteStrategyB>();}return nullptr;}
};// 上下文類
class Context {
private:std::unique_ptr<Strategy> strategy;
public:Context(std::unique_ptr<Strategy> s) : strategy(std::move(s)) {}void setStrategy(std::unique_ptr<Strategy> s) {strategy = std::move(s);}void executeStrategy() {if (strategy) {strategy->execute();}}
};int main() {auto strategyA = StrategyFactory::createStrategy("A");Context context(std::move(strategyA));context.executeStrategy();auto strategyB = StrategyFactory::createStrategy("B");context.setStrategy(std::move(strategyB));context.executeStrategy();return 0;
}
4.2.3 策略參數化
有時候,具體策略類的算法可能需要一些參數。我們可以在策略接口或具體策略類中添加相應的參數。
#include <iostream>
#include <memory>// 策略接口
class Strategy {
public:virtual void execute(int param) = 0;virtual ~Strategy() {}
};// 具體策略類A
class ConcreteStrategyA : public Strategy {
public:void execute(int param) override {std::cout << "Executing strategy A with parameter: " << param << std::endl;}
};// 具體策略類B
class ConcreteStrategyB : public Strategy {
public:void execute(int param) override {std::cout << "Executing strategy B with parameter: " << param << std::endl;}
};// 上下文類
class Context {
private:std::unique_ptr<Strategy> strategy;
public:Context(std::unique_ptr<Strategy> s) : strategy(std::move(s)) {}void setStrategy(std::unique_ptr<Strategy> s) {strategy = std::move(s);}void executeStrategy(int param) {if (strategy) {strategy->execute(param);}}
};int main() {auto strategyA = std::make_unique<ConcreteStrategyA>();Context context(std::move(strategyA));context.executeStrategy(10);auto strategyB = std::make_unique<ConcreteStrategyB>();context.setStrategy(std::move(strategyB));context.executeStrategy(20);return 0;
}
五、常見問題及解決方案
5.1 常見問題分析
5.1.1 策略類數量過多
當系統中有很多種算法時,會導致具體策略類的數量過多,增加了代碼的維護難度。
5.1.2 客戶端需要了解所有策略類
客戶端需要知道所有的具體策略類,并且在選擇策略時需要進行復雜的判斷,這增加了客戶端代碼的復雜度。
5.1.3 策略類之間的依賴關系
有些策略類可能依賴于其他的類或資源,這會導致策略類之間的耦合度增加,影響代碼的可維護性和可擴展性。
5.1.4 策略的初始化和銷毀
如果策略類需要進行復雜的初始化和銷毀操作,那么在上下文類中管理這些操作會變得困難。
5.2 解決方案
5.2.1 策略類的合并與分組
對于一些功能相似的策略類,可以將它們合并成一個策略類,或者將它們分組,減少策略類的數量。例如,將一些排序算法中通用的部分提取出來,放在一個基類中,然后不同的排序算法繼承自這個基類。
5.2.2 使用工廠模式或配置文件
通過工廠模式或配置文件來隱藏具體策略類的創建過程,客戶端只需要提供一個簡單的標識(如策略名稱),由工廠類或配置文件來創建相應的策略對象。這樣可以降低客戶端代碼的復雜度。
5.2.3 依賴注入
使用依賴注入的方式來解決策略類之間的依賴關系。將策略類依賴的對象通過構造函數或方法參數傳遞給策略類,而不是在策略類內部創建這些對象。這樣可以降低策略類之間的耦合度。
5.2.4 資源管理類
對于需要進行復雜初始化和銷毀操作的策略類,可以創建一個資源管理類來管理這些操作。資源管理類負責策略類的初始化和銷毀,上下文類只需要與資源管理類交互,而不需要關心具體的初始化和銷毀細節。
以下是一個使用依賴注入和資源管理類的示例:
#include <iostream>
#include <memory>// 依賴的資源類
class Resource {
public:Resource() {std::cout << "Resource initialized" << std::endl;}~Resource() {std::cout << "Resource destroyed" << std::endl;}void use() {std::cout << "Using resource" << std::endl;}
};// 策略接口
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() {}
};// 具體策略類
class ConcreteStrategy : public Strategy {
private:std::shared_ptr<Resource> resource;
public:ConcreteStrategy(std::shared_ptr<Resource> r) : resource(r) {}void execute() override {if (resource) {resource->use();}}
};// 資源管理類
class ResourceManager {
private:std::shared_ptr<Resource> resource;
public:ResourceManager() : resource(std::make_shared<Resource>()) {}std::shared_ptr<Resource> getResource() {return resource;}
};// 上下文類
class Context {
private:std::unique_ptr<Strategy> strategy;
public:Context(std::unique_ptr<Strategy> s) : strategy(std::move(s)) {}void executeStrategy() {if (strategy) {strategy->execute();}}
};int main() {ResourceManager resourceManager;auto resource = resourceManager.getResource();auto strategy = std::make_unique<ConcreteStrategy>(resource);Context context(std::move(strategy));context.executeStrategy();return 0;
}
在這個示例中,Resource 類是策略類依賴的資源類,ConcreteStrategy 類通過構造函數接收一個 std::shared_ptr 對象,實現了依賴注入。ResourceManager 類負責資源的初始化和管理,Context 類只需要與 ConcreteStrategy 類交互,不需要關心資源的初始化和銷毀細節。
六、總結
6.1 模式優點
可擴展性強:當需要新增一種算法時,只需要創建一個新的具體策略類,而不需要修改現有的代碼,符合開閉原則。
代碼復用性高:每個具體策略類封裝了自己的算法,這些算法可以在不同的地方復用。
可維護性好:策略模式將算法的定義和使用分離,使代碼結構更加清晰,易于維護。
靈活性高:可以在運行時動態地切換策略,根據不同的需求選擇合適的算法。
6.2 模式缺點
策略類數量過多:當系統中有很多種算法時,會導致具體策略類的數量過多,增加了代碼的維護難度。
客戶端復雜度增加:客戶端需要了解所有的具體策略類,并且在選擇策略時需要進行復雜的判斷,增加了客戶端代碼的復雜度。
內存開銷:每個具體策略類都需要占用一定的內存空間,如果策略類數量過多,會增加內存開銷。
6.3 最佳實踐建議
合理設計策略接口:策略接口應該定義清晰,只包含必要的方法,避免接口過于復雜。
使用工廠模式或配置文件:通過工廠模式或配置文件來隱藏具體策略類的創建過程,降低客戶端代碼的復雜度。
注意策略類的生命周期管理:使用智能指針等方式來管理策略類的生命周期,避免內存泄漏。
控制策略類的數量:對于功能相似的策略類,可以進行合并或分組,減少策略類的數量。
6.4 未來發展趨勢
隨著軟件系統的不斷發展,策略模式可能會與其他設計模式結合使用,以滿足更復雜的需求。例如,與狀態模式結合,根據系統的不同狀態選擇不同的策略;與觀察者模式結合,當系統的某些條件發生變化時,動態地切換策略。
同時,隨著人工智能和機器學習的發展,策略模式可能會在算法選擇和優化方面發揮更大的作用,根據數據的特點和模型的性能選擇合適的算法。
策略模式是一種非常實用的設計模式,它可以幫助我們提高代碼的可維護性、可擴展性和靈活性。在實際應用中,我們應該根據具體的需求和場景,合理地使用策略模式,并結合其他設計模式和技術,構建出更加健壯和高效的軟件系統。