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

news2024/9/20 14:54:04

一,策略模式简介

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

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

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

策略模式将不同的算法实现封装成独立的类,使得算法的修改不会影响到客户端代码,提高了应用程序的灵活性和可维护性。策略模式的架构可以避免使用大量的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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2118213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【运维监控】influxdb 2.0+grafana 监控java 虚拟机以及方法耗时情况(2)

关于java应用的监控本系列有文章如下&#xff1a; 【运维监控】influxdb 2.0telegraf 监控tomcat 8.5运行情况 【运维监控】influxdb 2.0grafana 监控java 虚拟机以及方法耗时情况 【运维监控】Prometheusgrafana监控tomcat运行情况 【运维监控】Prometheusgrafana监控spring b…

【即时通讯】轮询方式实现

技术栈 LayUI、jQuery实现前端效果。django4.2、django-ninja实现后端接口。 代码仓 - 后端 代码仓 - 前端 实现功能 首次访问页面并发送消息时需要设置昵称发送内容为空时要提示用户不能发送空消息前端定时获取消息&#xff0c;然后展示在页面上。 效果展示 首次发送需要…

【java入门】八大基本数据类型与变量的声明与使用,超详细讲解!

&#x1f680; 个人简介&#xff1a;某大型国企资深软件开发工程师&#xff0c;信息系统项目管理师、CSDN优质创作者、阿里云专家博主&#xff0c;华为云云享专家&#xff0c;分享前端后端相关技术与工作常见问题~ &#x1f49f; 作 者&#xff1a;码喽的自我修养&#x1f9…

【PyCharm使用教程】PyCharm的基本使用教程,适合完全零基础,小白快速上手!(Python+PyCharm安装包)

如果你正在学习Python&#xff0c;但是找不到方向的话可以试试我这一份学习方法和籽料呀&#xff01;点击 [领取籽料]&#xff08;不要米米&#xff09; Pycharm的基本使用教程 【一】PIP换源 ①问题描述 在使用Python时需要经常用到pip安装第三方包。在某些情况下由于网络速…

基于C++实现(控制台)学生成绩管理系统

学生成绩管理系统 一、系统需求分析 一个巨大的学校有数以万计的教工、学生和相应的资料需要管理。一个好的学生成绩管理系统可以协助管理员管理巨大的数据库&#xff0c;允许管理员、教师跟学生这三种用户登录进行相应的操作。 管理员具有管理数据库的一切权限。管理员负责…

兔英语语法体系——观后笔记

目录 一、视频链接 二、视频前言 三、简单句(Simple Sentences) 1. 可独立完成的动作 2. 有1个动作的承受者 3. 有两个动作承受者 4. 只有一个动作承受者(但需补充) 5. 非 “动作” 6. 总结 四、五大基本句型 五、句子成分 6. 定语 7. 状语 8. 同位语 9. 总结 …

[SWPUCTF 2022 新生赛]

目录 [SWPUCTF 2022 新生赛]ez_rce 什么是poc&#xff1f; [SWPUCTF 2022 新生赛]where_am_i [SWPUCTF 2022 新生赛]js_sign [SWPUCTF 2022 新生赛]xff ​[SWPUCTF 2022 新生赛]numgame call_user_func()函数 ::双冒号运算符 [SWPUCTF 2022 新生赛]ez_sql [SWPUCTF 2…

Anylogic比较运行实验

比较运行实验案例&#xff1a; 设置好参数后&#xff0c;点击左下角的开始&#xff0c;即可运算出结果 设置图例参数&#xff0c;在界面上图例显示为改变的变量值&#xff1a;

雕虫小技:解决VSCode中extern “C“的代码缩进问题

问题现象 创建一个标准的C语言头文件&#xff1a;foo.h #ifndef _FOO_H_ #define _FOO_H_#ifdef __cplusplus extern "C" { #endif/************************************************************************** * Include Files …

Security(lt2)

some basic terminology • plaintext - original message • ciphertext - coded message • cipher - algorithm for transforming plaintext to ciphertext • key - info used in cipher known only to sender/receiver • encipher (encrypt) - converting plaintext to …

从fasta文件中提取指定长度序列构建矩阵

要从 FASTA 文件中提取指定长度的序列并构建矩阵&#xff0c;你可以使用 BioPython 库&#xff0c;它可以方便地处理生物序列数据。你可以通过从 FASTA 文件中读取序列&#xff0c;然后将每个序列拆分成指定长度的子序列&#xff0c;最终构建矩阵。 以下是一个示例代码&#x…

深兰科技董事长陈海波出席《中马建交五十周年高级别经贸合作》

2024年9月3日&#xff0c;中马建交50周年高级别经贸合作交流会暨马来西亚第九任首相VIP欢迎晚宴在北京隆重举行&#xff0c;深兰科技创始人、董事长陈海波先生应邀出席。 会议期间&#xff0c;双方举行了品牌出海合作签约仪式。在马来西亚首相雅各布先生的见证下&#xff0c;深…

分解+优化+组合+对比!核心无忧!VMD-SSA-Transformer-LSTM多变量时间序列光伏功率预测

分解优化组合对比&#xff01;核心无忧&#xff01;VMD-SSA-Transformer-LSTM多变量时间序列光伏功率预测 目录 分解优化组合对比&#xff01;核心无忧&#xff01;VMD-SSA-Transformer-LSTM多变量时间序列光伏功率预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.…

万字长文带你窥探Spring中所有的扩展点

写在前面 Spring的核心思想就是容器&#xff0c;当容器refresh的时候&#xff0c;外部看上去风平浪静&#xff0c;其实内部则是一片惊涛骇浪&#xff0c;汪洋一片。Springboot更是封装了Spring&#xff0c;遵循约定大于配置&#xff0c;加上自动装配的机制。很多时候我们只要引…

直流负载技术介绍

直流负载技术是一种用于控制和调节电力系统运行状态的重要技术。它主要通过对电力系统中的直流负载进行有效的管理和控制&#xff0c;以保证电力系统的稳定运行&#xff0c;提高电力系统的运行效率&#xff0c;降低电力系统的运行成本。 直流负载技术主要包括直流负载的检测、…

csdn有xss漏洞吗?

csdn有xss漏洞吗&#xff1f; 图片111&#xff1f;

GNU风格代码编译(27)

1makefile 的规则 命令必须使用tab 按键&#xff0c; 而不能使用 空格按键。 1. TARGETstart 2. TARGETCmain 3. all: 4. arm-none-linux-gnueabi-gcc -O0 -g -c -o $(TARGETC).o $(TARGETC).c 5. arm-none-linux-gnueabi-gcc -O0 -g -c -o $(TARGET).o $(TARGET).s…

米壳AI:分享一个轻松保存外网高清原视频的方法!

hello&#xff01;各位小伙伴们&#xff0c;你们好呀&#xff01;今天我要给大家分享一个超级实用的工具 ——medio.cool。 在这个信息全球化的时代&#xff0c;我们常常会被国外的精彩视频所吸引&#xff0c;然而如果我们想到外网下载视频&#xff0c;最高只可以保存 720p 的画…

AI 智能体: 一篇文章,解锁你的第一张 Coze 卡片

你是否和我一样&#xff0c;看多了用大量文字堆积的回复结果就会感到腻呢&#xff1f; 相比于枯燥乏味的文字&#xff0c;大家更喜欢图文并茂的呈现方式。 图片中&#xff0c;左侧是生成的卡片&#xff0c;右侧是没有配置卡片的效果。你会选哪一个&#xff1f; 或许&#xf…

假期学习-- iOS 通知详解

iOS 通知详解 数据结构 从我们之前使用通知的流程和代码来看&#xff0c;通知其实就是一个单例&#xff0c;方便随时访问。 NSNotificationCenter&#xff1a;消息中心 这个单例类中主要定义了两个表&#xff0c;一个存储所有注册通知信息的表的结构体&#xff0c;一个保存…