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

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基