C++11 设计模式7 策略模式 ,Strategy

2024-05-01 05:36

本文主要是介绍C++11 设计模式7 策略模式 ,Strategy,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

策略模式的概念:

策略模式(Strategy Pattern)是 C++ 中常用的一种行为设计模式,它能在运行时改变对象的行为。在策略模式中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。

在策略模式中,需要创建表示各种策略的对象和一个行为随着策略对象改变而改变的 Context 对象。策略对象更改 Context 对象的执行算法。

在策略模式中,通常包括以下几个角色:

(1)策略接口(Strategy Interface): 定义了一个策略的公共接口,所有具体的策略类都需要实现这个接口。这个接口声明了策略对象将执行的操作。

(2)具体策略类(Concrete Strategy Classes): 实现了策略接口,提供了具体的算法或行为。每个具体策略类都封装了实现特定行为或算法的代码。

(3)上下文(Context): 维护一个指向策略对象的引用,并定义一个接口来让策略对象执行其算法。上下文类并不知道具体的策略类,它只知道策略接口。这样,上下文可以将请求转发给当前关联的策略对象来执行。

2 策略模式的实现步骤
在 C++ 实现策略模式的实现步骤如下:

(1)定义策略接口:
首先,需要定义一个策略接口。这个接口通常是一个纯虚类,声明了一组公共的、需要由具体策略类来实现的方法。这些方法是策略对象将执行的行为的抽象描述。

(2)实现具体策略类:
接下来,创建实现策略接口的具体策略类。每个具体策略类都包含了实现特定算法或行为的代码。这些类继承了策略接口,并实现了接口中声明的所有方法。

(3)创建上下文类:
上下文类负责维护对策略对象的引用,并定义了一个接口,以便客户端代码可以通过这个接口来执行策略对象的方法。上下文类通常包含一个指向策略接口的指针或引用,并通过这个指针或引用来调用策略方法。上下文类本身并不关心具体使用了哪个策略,它只关心策略接口。

(4)在上下文中设置策略对象:
在客户端代码中,创建具体策略类的对象,并将其传递给上下文对象。上下文对象使用这个策略对象来执行相应的算法或行为。客户端代码可以通过调用上下文类的方法来间接调用策略对象的方法。

(5)执行策略:
客户端代码通过调用上下文类的执行方法(例如 executeStrategy()),来触发策略的执行。上下文类将调用当前设置的策略对象的方法,实现相应的算法或行为。

(6)更改策略:
如果需要改变行为,客户端代码可以创建另一个策略对象,并将其设置为上下文对象的新策略。这样,上下文对象在执行策略时会使用新的算法或行为。

通过这些步骤,策略模式允许在运行时动态地改变对象的行为,提高了代码的灵活性和可维护性。它通过将算法和行为封装在独立的策略类中,实现了算法与使用算法的客户端代码之间的解耦。这样,客户端代码只需关注于如何使用策略,而不需要关心策略的具体实现。

#include <iostream>  
#include <memory>// 步骤1: 定义策略接口  
class Strategy {
public:virtual ~Strategy() {}virtual void execute() = 0;
};// 步骤2: 实现具体策略类  
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout << "Executing strategy A" << std::endl;}
};class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout << "Executing strategy B" << std::endl;}
};// 步骤3: 创建上下文类  
class Context {
public:// 通过构造函数设置策略  Context(std::unique_ptr<Strategy> strategy) : strategy(std::move(strategy)) {}// 执行策略  void executeStrategy() {if (strategy) {strategy->execute();}else {std::cout << "No strategy is set." << std::endl;}}// 更改策略  void setStrategy(std::unique_ptr<Strategy> newStrategy) {strategy = std::move(newStrategy);}private:std::unique_ptr<Strategy> strategy; // 使用unique_ptr管理策略对象的生命周期  
};// 步骤4-6: 在客户端代码中设置和执行策略  
int main() 
{// 创建具体策略对象并使用unique_ptr管理  auto strategyA = std::make_unique<ConcreteStrategyA>();auto strategyB = std::make_unique<ConcreteStrategyB>();// 创建上下文对象并设置初始策略  Context context(std::move(strategyA));context.executeStrategy(); // 输出:Executing strategy A  // 更改策略  context.setStrategy(std::move(strategyB));context.executeStrategy(); // 输出:Executing strategy B  // 此时strategyA和strategyB已经被unique_ptr自动释放  return 0;
}

假设公司是有一个算税法的函数。

不同的国家有不同的算税法的逻辑。

刚开始有三个国家,china,us,japan

你可能这么写:

//不同的国家有不同的算税法的逻辑。各个国家会根据不同销售额计算税率
//
//刚开始有三个国家,china,us,japan
//
//你可能这么写:#include <iostream>
using namespace std;enum TaxCountry {china_tax,us_tax,japan_tax
};//销售额类
class SaleOrder {
public:SaleOrder(int oneyeassalenum) {onesalemoney = oneyeassalenum;}int calculateTax() {if (taxcoutury== china_tax) {//如果是中国return onesalemoney / 3;}else if (taxcoutury == us_tax) {return onesalemoney / 2;}else if (taxcoutury == japan_tax) {return onesalemoney / 4;}}void setTaxCountry(TaxCountry _taxcoutury) {taxcoutury = _taxcoutury;}private:TaxCountry taxcoutury;int onesalemoney;
};int main()
{std::cout << "Hello World!\n";SaleOrder so(100);so.setTaxCountry(TaxCountry::china_tax);int result = so.calculateTax();cout << "result = " << result << endl;
}

但是随着业务的扩展,我们可能还要做德国的,法国的,印度的

那么这就要改动代码了,不符合开闭原则。

使用 策略模式改动

// 005策略模式.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//假设我们是做
//不同的国家有不同的算税法的逻辑。各个国家会根据不同销售额计算税率
//
//刚开始有三个国家,china,us,japan
//
//你可能这么写:#include <iostream>
using namespace std;enum TaxCountry {china_tax,us_tax,japan_tax
};//销售额类
class SaleOrder {
public:SaleOrder(int oneyeassalenum) {onesalemoney = oneyeassalenum;}int calculateTax() {if (taxcoutury== china_tax) {//如果是中国return onesalemoney / 3;}else if (taxcoutury == us_tax) {return onesalemoney / 2;}else if (taxcoutury == japan_tax) {return onesalemoney / 4;}}void setTaxCountry(TaxCountry _taxcoutury) {taxcoutury = _taxcoutury;}private:TaxCountry taxcoutury;int onesalemoney;
};int main005()
{std::cout << "Hello World!\n";SaleOrder so(100);so.setTaxCountry(TaxCountry::china_tax);int result = so.calculateTax();cout << "result = " << result << endl;return 0;
}// 策略基类
class TaxStrategy {
public:virtual int calculateTax(int onesalemoney) = 0;virtual ~TaxStrategy() {}
};// china策略实现
class ChinaTaxStrategy : public TaxStrategy {
public:int calculateTax(int onesalemoney) override {cout << "china calculateTax" << endl;return onesalemoney / 3;}
};// us 策略实现
class USTaxStrategy : public TaxStrategy {
public:int calculateTax(int onesalemoney) override {cout << "us calculateTax" << endl;return onesalemoney / 2;}
};//japan 策略实现
class JapanTaxStrategy : public TaxStrategy {
public:int calculateTax(int onesalemoney) override {cout << "japan calculateTax" << endl;return onesalemoney / 4;}
};//法国策略实现
class FranceTaxStrategy : public TaxStrategy {
public:int calculateTax(int onesalemoney) override {cout << "france calculateTax" << endl;return onesalemoney / 5;}
};// 上下文类
class Context {
private:TaxStrategy* strategy;int oneyearmoney;
public:Context(TaxStrategy* s, int money) : strategy(s), oneyearmoney(money){}int ContextInterface() {return strategy->calculateTax(oneyearmoney);}
};int main() {_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口TaxStrategy * ts = NULL;ts = new ChinaTaxStrategy();int result  = ts->calculateTax(1000);cout << "result = " << result << endl;delete ts;//	也可以通过创建一个上下文来处理// 创建具体策略对象TaxStrategy* strategyA = new ChinaTaxStrategy();TaxStrategy* strategyB = new USTaxStrategy();// 设置策略并调用Context* contextChina = new Context(strategyA,10000);result = contextChina->ContextInterface();cout << "result = " << result << endl;Context* contextUS = new Context(strategyB,200000);result = contextUS->ContextInterface();cout << "result = " << result << endl;delete contextUS;delete contextChina;delete strategyB;delete strategyA;return 0;
}

这篇关于C++11 设计模式7 策略模式 ,Strategy的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/950826

相关文章

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二