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…