C++设计模式——Strategy策略模式

2024-09-04 09:44

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

一,策略模式简介

策略模式是一种行为型设计模式,策略模式在软件开发场景中定义了一系列的算法,并将每个算法单独封装在可替换的对象中,使应用程序在运行时可以根据具体的上下文来动态地选择和切换算法,同时保持原有的代码架构不被修改。

策略模式的设计使得算法的实现与调用被分离,让算法可以独立于外部客户端进行开发和改动,使用独立的类来封装特定的算法,也避免了不同算法策略之间的互相影响。

策略模式能适应多种应用场景,为了满足业务需求,应用程序在运行时可以选择不同的算法策略来达到最优的实现效果。

策略模式将不同的算法实现封装成独立的类,使得算法的修改不会影响到客户端代码,提高了应用程序的灵活性和可维护性。策略模式的架构可以避免使用大量的if-else条件语句来大量判断不同的策略分支,优化了代码结构,增加了代码的可扩展性。

策略模式在现实生活中的抽象实例:

交通路线选择:当我们在规划行程路线时,根据行驶时间、行驶距离,可以规划出好几个不同的路线策略。

投资策略选择:投资者在选择投资策略时,可能会考虑不同的策略,比如价值、成长、指数等。

健身计划选择:在健身时,个人根据不同的健身进展选择不同的策略,如有氧运动、力量训练、高强度间歇训练等。

二,策略模式的结构

策略模式主要包含以下组件:

1.策略上下文(Context):

Context类是策略模式的调度核心,其内部包含了一个策略对象,并通过调用具体的策略对象来完成具体操作。Context类对外提供了与客户端交互的API接口,并隐藏了具体的算法细节,Context类相当于一个中间件,将算法封装与客户端调用进行了分离。

2.抽象策略类(Strategy):

Strategy类定义了一个公共接口,该公共接口最终将被具体的算法模块进行实现和重写。

3.具体策略类(ConcreteStrategy):

ConcreteStrategy类实现了Strategy类定义的公共接口,每一个具体策略类都包含特定的算法实现细节,并用来处理特定的应用场景。

组件之间的工作步骤如下:

1.客户端根据业务需要选择一个具体策略类,并初始化一个对应的策略对象。

2.客户端将创建好的策略对象传递给策略上下文。

3.策略上下文调用策略对象的接口函数。

4.当客户端需要更换算法策略时,可以重新选择一个具体策略类,并传递一个新的策略对象给策略上下文。

对应UML类图:

三,策略模式代码样例

Demo1:根据不同的策略,计算出不同的结果

#include <iostream>class Strategy {
public:virtual int operation(int input) const = 0;
};class ConcreteStrategyA : public Strategy {
public:int operation(int input) const override {return input * 2;}
};class ConcreteStrategyB : public Strategy {
public:int operation(int input) const override {return input / 2;}
};class Context {
private:Strategy* strategy;
public:Context(Strategy* strategy = nullptr) {this->strategy = strategy;}void setStrategy(Strategy* strategy) {this->strategy = strategy;}int execute(int input) const {return strategy->operation(input);}
};int main() {Context context(new ConcreteStrategyA());std::cout << "Using Strategy A: " << context.execute(10) << std::endl;context.setStrategy(new ConcreteStrategyB()); std::cout << "Using Strategy B: " << context.execute(10) << std::endl;return 0;
}

运行结果:

Using Strategy A: 20
Using Strategy B: 5

Demo2:根据不同的策略,打印不同的提示语

#include <iostream>class Strategy {
public:virtual void execute() const = 0;
};class ConcreteStrategyA : public Strategy {
public:virtual void execute() const override {std::cout << "Using Strategy A." << std::endl;}
};class ConcreteStrategyB : public Strategy {
public:virtual void execute() const override {std::cout << "Using Strategy B." << std::endl;}
};class Context {
private:Strategy* strategy;
public:Context(Strategy* strategy) : strategy(strategy) {}void setStrategy(Strategy* strategy) {this->strategy = strategy;}void executeStrategy() const {strategy->execute();}
};int main() {Strategy* strategyA = new ConcreteStrategyA();Strategy* strategyB = new ConcreteStrategyB();Context context(strategyA);context.executeStrategy();context.setStrategy(strategyB);context.executeStrategy();delete strategyA;delete strategyB;return 0;
}

运行结果:

Using Strategy A.
Using Strategy B.

四,策略模式的应用场景

文件格式处理:代码可以根据不同的文件格式选择不同的解析策略,例如文本格式、XML、JSON等。

交易系统开发:系统根据交易类型、支付渠道等,选择不同的处理策略。

可配置应用开发:用户可以根据不同的业务场景来动态选择不同的配置模板。

通用API开发:当同一个API需要提供多个版本或业务逻辑时,策略模式可以帮助隐藏具体细节。

五,策略模式的优缺点

策略模式的优点:

对“开闭原则”提供完美支持。

基于上下文和算法类的封装,方便管理和调度一系列算法策略。

避免了if-else条件语句的大量使用。

支持灵活的替换算法策略,代码的可读性和扩展性很强。

算法被封装以后,可以独立地被多个客户端和上下文复用。

策略模式的缺点:

使类和对象的数量变得更多,增加了系统的复杂性。

如果策略被划分得过于细化,会导致过度设计,不易于代码理解。

代码涉及多个对象的创建和销毁,性能开销增大,大量使用会引起性能问题。

六,代码实战

Demo:集成冒泡排序算法、选择排序算法给客户端进行调用

#include <iostream>
#include <vector>class SortingStrategy {
public:virtual void sort(std::vector<int>& arr) = 0;
};class BubbleSort: public SortingStrategy {
public:void sort(std::vector<int>& arr) override{std::cout << "\nUse Strategy: BubbleSort." << std::endl;int n = arr.size();for (size_t i = 0; i < n - 1; ++i) {for (size_t j = 0; j < n - i - 1; ++j) {if (arr[j] > arr[j + 1]) {std::swap(arr[j], arr[j + 1]);}}}}
};class SelectionSort: public SortingStrategy {
public:void sort(std::vector<int>& arr) override{std::cout << "\nUse Strategy: SelectionSort." << std::endl;int n = arr.size();for (int i = 0; i < n - 1; ++i) {int minIndex = i;for (int j = i + 1; j < n; ++j) {if (arr[j] < arr[minIndex]) {minIndex = j;}}std::swap(arr[i], arr[minIndex]);}}
};class SortContext {
private:SortingStrategy* strategy;public:void setStrategy(SortingStrategy* strategy){this->strategy = strategy;}void executeStrategy(std::vector<int>& arr){strategy->sort(arr);}
};int main()
{std::vector<int> data = { 23, 5, 6, 36, 25, 4, 20 };SortContext context;BubbleSort bubbleSort;SelectionSort selectSort;context.setStrategy(&bubbleSort);context.executeStrategy(data);for (const auto& num : data) {std::cout << num << " ";}data = { 32, 45, 5, 6, 100, 7 };context.setStrategy(&selectSort);context.executeStrategy(data);for (const auto& num : data) {std::cout << num << " ";}return 0;
}

运行结果:

Use Strategy: BubbleSort.
4 5 6 20 23 25 36
Use Strategy: SelectionSort.
5 6 7 32 45 100

七,参考阅读

https://www.geeksforgeeks.org/strategy-method-design-pattern-c-design-patterns/

https://refactoringguru.cn/design-patterns/strategy

https://design-patterns.readthedocs.io/zh-cn/latest/behavioral_patterns/strategy.html

https://www.vishalchovatiya.com/strategy-design-pattern-in-modern-cpp/

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



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

相关文章

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一