【C++設計模式】第二篇:策略模式(Strategy)--從基本介紹,內部原理、應用場景、使用方法,常見問題和解決方案進行深度解析

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 未來發展趨勢

隨著軟件系統的不斷發展,策略模式可能會與其他設計模式結合使用,以滿足更復雜的需求。例如,與狀態模式結合,根據系統的不同狀態選擇不同的策略;與觀察者模式結合,當系統的某些條件發生變化時,動態地切換策略。
同時,隨著人工智能和機器學習的發展,策略模式可能會在算法選擇和優化方面發揮更大的作用,根據數據的特點和模型的性能選擇合適的算法。
策略模式是一種非常實用的設計模式,它可以幫助我們提高代碼的可維護性、可擴展性和靈活性。在實際應用中,我們應該根據具體的需求和場景,合理地使用策略模式,并結合其他設計模式和技術,構建出更加健壯和高效的軟件系統。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95697.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

四十歲編程:熱愛、沉淀與行業的真相-優雅草卓伊凡

四十歲編程&#xff1a;熱愛、沉淀與行業的真相-優雅草卓伊凡今日卓伊凡收到一個問題&#xff1a;「如何看待40歲還在擼代碼的程序員&#xff1f;」這讓我不禁思考&#xff1a;從何時起&#xff0c;年齡成了程序員職業中的敏感詞&#xff1f;在互聯網的某些角落&#xff0c;彌漫…

pycharm解釋器使用anaconda建立的虛擬環境里面的python,無需系統里面安裝python。

Anaconda建立的虛擬環境可以在虛擬環境里設置任何的python版本&#xff0c;pycharm解釋器使用anaconda建立的虛擬環境里面的python&#xff0c;比如anaconda建立的虛擬環境1、虛擬環境2&#xff0c;pycharm解釋器使用anaconda建立虛擬環境1也可以使用虛擬環境2&#xff0c;根本…

機器學習:后篇

目錄 一、KNN算法-分類 樣本距離 KNN算法原理 缺點 API 二、模型選擇與調優 交叉驗證 保留交叉驗證(HoldOut) k-折交叉驗證(K-fold) 分層k-折交叉驗證(Stratified k-fold) 其他交叉驗證 三、樸素貝葉斯-分類 理論介紹 拉普拉斯平滑系數 API 四、決策樹-分類 理論…

C++17無鎖編程實戰

在多線程編程里&#xff0c;“鎖” 這東西就像把雙刃劍 —— 用好了能保數據安全&#xff0c;用不好就麻煩了&#xff1a;大粒度的鎖把并發度壓得死死的&#xff0c;稍不注意加錯鎖還可能搞出死鎖&#xff0c;程序直接 “僵住”。 但如果能擺脫鎖&#xff0c;搞出支持安全并發…

SVT-AV1 svt_aom_motion_estimation_kernel 函數分析

void *svt_aom_motion_estimation_kernel(void *input_ptr) // 運動估計內核主函數&#xff0c;接收線程輸入參數{// 從輸入參數中獲取線程上下文指針EbThreadContext * thread_ctx (EbThreadContext *)input_ptr;// 從線程上下文中獲取運動估計上下文指針MotionEstimationCon…

關于NET Core jwt Bearer Token 驗證的大坑,浪費3個小時,給各位兄弟搭個橋。

net core 使用jwt Bearer Token 認證獲取接口訪問權限&#xff0c;前期一陣操作沒任何問題&#xff0c;等認證接口寫的好了&#xff0c;通過PostMan測試的時候&#xff0c;總是報一個 IDX14102: Unable to decode the header eyJhbGciOiJIUzI1NiIsInR5cCI6 &#xff0c;錯誤&a…

系統架構設計師備考第14天——業務處理系統(TPS)

一、TPS的核心概念與定位 1. 定義與演進 定義&#xff1a;TPS&#xff08;Transaction Processing System&#xff09;又稱電子數據處理系統&#xff08;EDPS&#xff09;&#xff0c;是處理企業日常事務的信息系統&#xff0c;如財務、庫存、銷售等局部業務管理。歷史地位&…

目標檢測系列-Yolov5下載及運行

由于項目需要&#xff0c;最近一直在看目標檢測相關的資料&#xff0c;不過紙上得來終覺淺&#xff0c;絕知此事要躬行啊。從今日起&#xff0c;將學習的過程記錄一下&#xff0c;作為以后用來復習的材料吧。 我想最快的學習便是直接動手做項目&#xff0c;因此今天就將yolov5模…

Linux內核進程管理子系統有什么第四十二回 —— 進程主結構詳解(38)

接前一篇文章&#xff1a;Linux內核進程管理子系統有什么第四十一回 —— 進程主結構詳解&#xff08;37&#xff09; 本文內容參考&#xff1a; Linux內核進程管理專題報告_linux rseq-CSDN博客 《趣談Linux操作系統 核心原理篇&#xff1a;第三部分 進程管理》—— 劉超 《…

基于飛算JavaAI的學生成績綜合統計分析系統

第一章&#xff1a;項目概述與背景 1.1 項目背景與意義 在教育信息化飛速發展的今天&#xff0c;學生成績管理已成為學校教學管理的核心環節。傳統的學生成績管理多依賴于手工操作或基礎的信息管理系統&#xff0c;存在數據處理效率低、統計分析功能薄弱、數據可視化缺失等問題…

C++程序員必懂:std::bad_function_call異常的真相與預防秘訣

std::bad_function_call 是 C++ 標準庫在 <functional> 頭文件中定義的一個異常類型。當程序試圖調用一個未持有任何可調用目標(即處于“空狀態”)的 std::function 對象時,此異常會被拋出。本文將深入探討該異常的根本原因、詳細的觸發場景,并提供一套完整的預防與處…

Html重繪和重排

在網頁渲染過程中&#xff0c;重繪&#xff08;repaint&#xff09;和重排&#xff08;reflow&#xff09;是兩個重要的概念。理解它們的區別和優化方法對于提升網頁性能至關重要。重排&#xff08;Reflow&#xff09;重排是指當頁面元素的位置、尺寸等幾何屬性發生變化時&…

Redis 客戶端與服務器:銀行的 “客戶服務系統” 全流程

目錄 一、Redis 客戶端&#xff1a;銀行的 “客戶檔案” 二、客戶端關閉&#xff1a;銀行的 “終止服務規則” 三、命令處理流程&#xff1a;柜員辦理業務的 “標準步驟” 1. 接收申請單&#xff08;讀取命令請求&#xff09; 2. 確認業務類型&#xff08;查找命令&#x…

HTML圖片標簽及路徑詳解

圖片是網頁內容的重要組成部分&#xff0c;能夠使頁面更加生動直觀。在HTML中&#xff0c;使用<img>標簽插入圖片&#xff0c;而正確設置圖片路徑則是確保圖片能夠正常顯示的關鍵。一、圖片標簽&#xff08;<img>&#xff09;1. 圖片標簽的基本語法<img>標簽…

【數據庫通過日志恢復數據解讀】

在數據庫恢復機制中&#xff0c;日志文件是實現事務原子性、持久性和崩潰恢復的核心組件。以下通過具體示例和解讀方法&#xff0c;結合主流數據庫系統的實現細節&#xff0c;詳細說明日志文件的內容與分析邏輯。 一、日志文件的核心作用與結構 日志文件通過**預寫式日志&#…

【面試題】搜索準確性不高你怎么排查?

系統性排查框架&#xff1a;數據層檢查 索引覆蓋率&#xff1a;檢查文檔是否全部正確索引數據新鮮度&#xff1a;確認索引更新頻率和延遲文檔質量&#xff1a;分析被索引內容的質量和完整性查詢理解層 分詞分析&#xff1a;檢查查詢分詞是否正確意圖識別&#xff1a;驗證意圖分…

當AI開始“偷吃”用戶數據并拼裝功能模塊:初級開發者的腦洞保衛戰與老碼農的靈魂蘸料

前言&#xff1a;哈嘍&#xff0c;大家好&#xff0c;今天給大家分享一篇文章&#xff01;并提供具體代碼幫助大家深入理解&#xff0c;徹底掌握&#xff01;創作不易&#xff0c;如果能幫助到大家或者給大家一些靈感和啟發&#xff0c;歡迎收藏關注哦 &#x1f495; 目錄當AI開…

Flowable——流程定義與部署(RepositoryService)

文章目錄 前言 參考資料 流程圖的部署、查詢與刪除 流程圖的準備 流程的部署 指定已部署流程信息查詢 刪除指定已部署流程 結語 前言 前篇博客具體說了怎么使用flowable去自動建表,以及搭建配置前端UI繪圖的界面。本篇博客主要說明對于已繪制好的流程圖如何去進行部署。 Flow…

采用基于模型的方法實現車輛SOA威脅分析自動化

摘要盡管采用面向服務架構&#xff08;SOA&#xff09;有助于實現自動駕駛、空中下載更新等功能&#xff0c;但同時也增加了車輛遭受攻擊的風險&#xff0c;可能對道路使用者造成傷害。為解決這一問題&#xff0c;相關標準&#xff08;ISO 21434 / 聯合國歐洲經濟委員會&#x…

C++語言編程規范-常量

01 C還有搞頭嗎 02 常量 不變的值更易于理解、跟蹤和分析&#xff0c;所以應該盡可能地使用常量代替變量&#xff0c;定義值的時候&#xff0c;應該把 const 作為默認的選項。使用 const 常量取代宏說明&#xff1a;宏是簡單的文本替換&#xff0c;在預處理階段時完成&#x…