【C++设计模式之Strategy策略模式】

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

  • 模式定义
  • 核心思想
  • 动机(Motivation)
  • 结构(Structure)
  • 实现步骤
    • 1. 定义策略接口(基于继承)
    • 2.实现具体策略
    • 3.上下文类(Context)
    • 4. 在main中调用
  • 应用场景(基于继承)
    • 1.定义策略接口
    • 2.实现具体策略
    • 3.上下文类(Context)
    • 4.在main中调用测试
  • 现代 C++ 优化(基于 std::function)
    • 1.使用函数对象替代接口
    • 2.定义策略函数
    • 3.main.cpp中使用示例
  • 优化方向
    • 1.编译时策略(模板实现)
    • 2.线程安全策略切换
  • 要点总结


模式定义

策略模式:定义一系列算法,把她们一个个封装起来,并且使它们可以相互替换(变化)。该模式使得算法可以独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
需要区分策略模式和之前提到的模板方法模式的不同,模板方法是通过继承来改变部分步骤,而策略模式是通过组合不同的策略对象来改变整体行为。

核心思想

  • 解耦算法与客户端:将算法逻辑从主类中分离,避免代码臃肿。
  • 运行时动态切换:通过更换策略对象,灵活改变程序行为。
  • 开闭原则:新增算法无需修改现有代码,只需添加新策略类。

动机(Motivation)

  • 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
  • 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

结构(Structure)

在这里插入图片描述

实现步骤

1. 定义策略接口(基于继承)

startegy.h

#pragma once
class Strategy {//策略模式的运算法则
public:virtual ~Strategy() {}virtual void doSomething() = 0;
};

2.实现具体策略

concretestrategy.h

#pragma once
#include<iostream>
#include"strategy.h"
class ConcreteStrategy1 :public Strategy {
public:void doSomething()override {std::cout << "ConcreteStrategy1 doSomething" << std::endl;}
};class ConcreteStrategy2 :public Strategy {
public:void doSomething()override {std::cout << "ConcreteStrategy2 doSomething" << std::endl;}
};

3.上下文类(Context)

持有策略对象的引用,并委托算法执行

context.h

#pragma once
#include"strategy.h"
class Context {
public://构造函数设置具体策略Context(Strategy *strategy) {strategy_ = strategy;}//封装后的策略方法void doAnything() {strategy_->doSomething();}private:Strategy *strategy_ = nullptr;
};

4. 在main中调用

#include "concretestrategy.h"
#include "context.h"int main()
{Strategy *strategy = new ConcreteStrategy1();//声明上下文对象Context context(strategy);context.doAnything();delete strategy;
}

应用场景(基于继承)

传统实现(基于继承),实现快速排序算法,归并排序算法的策略模式

1.定义策略接口

sortingstrategy.h

#pragma once
#include<iostream>
#include<vector>//策略接口:定义算法的抽象操作
class SortingStrategy {
public:virtual ~SortingStrategy() = default;virtual void sort(std::vector<int>&data)const = 0;
};

2.实现具体策略

#pragma once
#include"sortingstrategy.h"
//具体策略1:快速排序
class QuickSort :public SortingStrategy
{
public:void sort(std::vector<int>&data)const override {std::cout << "Sorting with QuickSort\n";//快速排序具体实现}
};class MergeSort :public SortingStrategy
{
public:void sort(std::vector<int>&data)const override {std::cout << "Sorting with MergeSort\n";//归并排序具体实现}
};

3.上下文类(Context)

持有策略对象的引用,并委托算法执行

context.h

#pragma once
#include"concretesorting.h"
class Sorter {
private:std::unique_ptr<SortingStrategy> strategy_;  //使用智能指针管理策略对象public:explicit Sorter(std::unique_ptr<SortingStrategy> strategy):strategy_(std::move(strategy)){}//动态切换策略void setStrategy(std::unique_ptr<SortingStrategy>strategy) {strategy_ = std::move(strategy);}//执行排序void executeSort(std::vector<int>&data)const {if (strategy_) {strategy_->sort(data);}}
};

4.在main中调用测试

#include"context.h"
#include<vector>int main()
{std::vector<int> data = { 5,2,7,1,9 };Sorter sorter(std::make_unique<QuickSort>());sorter.executeSort(data);    //输出:Sorting with QuickSortsorter.setStrategy(std::make_unique<MergeSort>());sorter.executeSort(data);    //输出Sorting with MergeSortreturn 0;
}

现代 C++ 优化(基于 std::function)

1.使用函数对象替代接口

无需继承策略接口,直接通过std::function封装算法:
context.h

#pragma once
#include<functional>
#include<vector>class Sorter {
public:using Strategy = std::function<void(std::vector<int>&)>;explicit Sorter(Strategy strategy):strategy_(std::move(strategy)){}void setStrategy(Strategy strategy) {strategy_ = std::move(strategy);}void executeSort(std::vector<int>&data)const {if (strategy_) {strategy_(data);}}private:Strategy strategy_;
};

2.定义策略函数

context.h

void quickSort(std::vector<int>& data) {std::cout << "Sorting with QuickSort\n";// 快速排序实现...
}void mergeSort(std::vector<int>& data) {std::cout << "Sorting with MergeSort\n";// 归并排序实现...
}// 支持 Lambda 表达式
auto bubbleSort = [](std::vector<int>& data) {std::cout << "Sorting with BubbleSort\n";// 冒泡排序实现...
};

3.main.cpp中使用示例

#include"context.h"int main()
{std::vector<int> data = { 5,2,7,1,9 };Sorter sorter(quickSort);sorter.executeSort(data);      //输出Sorting with QuickSortsorter.setStrategy(mergeSort); //输出Sorting with MergeSortsorter.executeSort(data);sorter.setStrategy(bubbleSort);//输出Sorting with BubbleSortsorter.executeSort(data);//直接传达Lambdasorter.setStrategy([](std::vector<int>&data) {std::cout << "Custom Lambda Strategy \n";});sorter.executeSort(data);return 0;
}

优化方向

1.编译时策略(模板实现)

通过模板参数在编译时绑定 策略,消除运行时开销:

#pragma once
#include<vector>
#include<iostream>template<typename Strategy>
class ComplieTimeSorter {
public:void executeSort(std::vector<int>&data)const {Strategy::sort(data);   //策略需要提供静态方法}
};//策略类无需继承接口
struct QuickSort {static void sort(std::vector<int>&data) {std::cout << "Compile-Time QuickSort \n";}
};int main()
{std::vector<int> data = { 5,2,7,1,9 };ComplieTimeSorter<QuickSort>sorter;sorter.executeSort(data);  //输出Complie-Time QuickSortsystem("pause");return 0;
}

2.线程安全策略切换

在多线程环境中安全且策略:

#pragma once
#include<mutex>
#include<vector>class ThreadSafeSorter {
public:using Strategy = std::function<void(std::vector<int>&)>;void setStrategy(Strategy strategy) {std::lock_guard<std::mutex>lock(mtx_);strategy_ = std::move(strategy);}void executeSort(std::vector<int>&data)const {std::lock_guard<std::mutex>lock(mtx_);if (strategy_) {strategy_(data);}}
private:mutable std::mutex mtx_;Strategy strategy_;
};

要点总结

  • Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
  • Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
  • 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

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

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

相关文章

Python企业级MySQL数据库开发实战指南

简介 Python与MySQL的完美结合是现代Web应用和数据分析系统的基石,能够创建高效稳定的企业级数据库解决方案。本文将从零开始,全面介绍如何使用Python连接MySQL数据库,设计健壮的表结构,实现CRUD操作,并掌握连接池管理、事务处理、批量操作和防止SQL注入等企业级开发核心…

matlab转python

1 matlab2python开源程序 https://blog.csdn.net/qq_43426078/article/details/123384265 2 网址 转换网址&#xff1a;https://app.codeconvert.ai/code-converter?inputLangMatlab&outputLangPython 文件比较网址&#xff1a;https://www.diffchecker.com/text-comp…

Vue 3 中编译时和运行时的概念区别

文章目录 前言Vue 3 中的编译时 vs 运行时区别模板在编译时转化为渲染函数编译时的优化处理运行时的工作:创建组件实例与渲染流程前言 详细整理 Vue 3 中编译时和运行时的概念区别,并重点解释为什么组件实例是在运行时创建的。 我会结合官方文档、源码分析和社区解释,确保内…

Spring 框架实战:如何实现高效的依赖注入,优化项目结构?

Spring 框架实战&#xff1a;如何实现高效的依赖注入&#xff0c;优化项目结构&#xff1f; 在当今的 Java 开发领域&#xff0c;Spring 框架占据着举足轻重的地位。而依赖注入作为 Spring 的核心概念之一&#xff0c;对于构建高效、灵活且易于维护的项目结构有着关键作用。本…

创建虚拟服务时实现持久连接。

在调度器中配置虚拟服务&#xff0c;实现持久性连接&#xff0c;解决会话保持问题。 -p 【timeout】 -p 300 这5分钟之内调度器会把来自同一个客户端的请求转发到同一个后端服务器。【不管使用的调度算法是什么。】【称为持久性连接。】 作用&#xff1a;将客户端一段时间…

说下RabbitMQ的整体架构

RabbitMQ 是一个基于 AMQP&#xff08;Advanced Message Queuing Protocol&#xff09; 协议的开源消息中间件&#xff0c;RabbitMQ的整体架构围绕消息的生产、路由、存储和消费设计&#xff0c;旨在实现高效、可靠的消息传递&#xff0c;它由多个核心组件协同工作。 核心组件 …

STM32--GPIO

教程 视频 博主教程 STM32系统结构图 GPIO GPIO&#xff08;General Purpose Input/Output&#xff09;是STM32内部的一种外设。 一个STM32芯片内存在多个GPIO外设&#xff0c;每个GPIO外设有16个引脚&#xff1b; 比如GPIOA&#xff1a;PA0~PA15; GPIOB&#xff1a;PB0~…

QUIC协议优化:HTTP_3环境下的超高速异步抓取方案

摘要 随着 QUIC 和 HTTP/3 的普及&#xff0c;基于 UDP 的连接复用与内置加密带来了远超 HTTP/2 的性能提升&#xff0c;可显著降低连接握手与拥塞恢复的开销。本文以爬取知乎热榜数据为目标&#xff0c;提出一种基于 HTTPX aioquic 的异步抓取方案&#xff0c;并结合代理 IP设…

[论文阅读]MCP Guardian: A Security-First Layer for Safeguarding MCP-Based AI System

MCP Guardian: A Security-First Layer for Safeguarding MCP-Based AI System http://arxiv.org/abs/2504.12757 推出了 MCP Guardian&#xff0c;这是一个框架&#xff0c;通过身份验证、速率限制、日志记录、跟踪和 Web 应用程序防火墙 &#xff08;WAF&#xff09; 扫描来…

Redis客户端缓存的4种实现方式

Redis作为当今最流行的内存数据库和缓存系统&#xff0c;被广泛应用于各类应用场景。然而&#xff0c;即使Redis本身性能卓越&#xff0c;在高并发场景下&#xff0c;应用与Redis服务器之间的网络通信仍可能成为性能瓶颈。 这时&#xff0c;客户端缓存技术便显得尤为重要。 客…

eNSP中路由器OSPF协议配置完整实验和命令解释

本实验使用三台华为路由器&#xff08;R1、R2和R3&#xff09;相连&#xff0c;配置OSPF协议实现网络互通。拓扑结构如下&#xff1a; 实验IP规划 R1: GE0/0/0: 192.168.12.1/24 (Area 0)Loopback0: 1.1.1.1/32 (Area 0) R2: GE0/0/0: 192.168.12.2/24 (Area 0)GE0/0/1: 192.…

内网渗透——红日靶场三

目录 一、前期准备 二、外网探测 1.使用nmap进行扫描 2.网站信息收集 3.漏洞复现(CVE-2021-23132) 4.disable_function绕过 5.反弹shell&#xff08;也&#xff0c;并不是&#xff09; 6.SSH登录 7.权限提升&#xff08;脏牛漏洞&#xff09; 8.信息收集 9.上线msf 三…

解决Win11下MySQL服务无法开机自启动问题

问题描述 在win11系统中&#xff0c;明明将MySQL服务设置成了自动启动&#xff0c;但在重启电脑后MySQL服务还是无法自动启动&#xff0c;每次都要重新到计算机管理的服务中找到服务再手动启动。 解决方式 首先确保mysql服务的启动类型为自动。 设置方法&#xff1a;找到此电…

后端项目进度汇报

项目概述 本项目致力于构建一个先进的智能任务自动化平台。其核心技术是一套由大型语言模型&#xff08;LLM&#xff09;驱动的后端系统。该系统能够模拟一个多角色协作的团队&#xff0c;通过一系列精心设计或动态生成的处理阶段&#xff0c;来高效完成各种复杂任务&#xff…

深度学习中学习率调整:提升食物图像分类模型性能的关键实践

深度学习中学习率调整&#xff1a;提升食物图像分类模型性能的关键实践 接上篇保存最优模型&#xff0c;在深度学习模型训练过程中&#xff0c;学习率作为核心超参数&#xff0c;其设置直接影响模型的收敛速度与最终性能。本文将结合食物图像分类项目&#xff0c;深入探讨学习…

Vue 3零基础入门:从环境搭建到第一个组件

Vue 3零基础入门&#xff1a;从环境搭建到第一个组件 一、Vue 3简介 Vue.js是一款渐进式JavaScript框架&#xff0c;用于构建用户界面。Vue 3是Vue的最新主要版本&#xff0c;于2020年9月发布&#xff0c;带来了许多改进和新特性&#xff1a; 更快的渲染速度更小的包体积Com…

为了结合后端而学习前端的学习日志(1)——纯CSS静态卡片案例

前端设计专栏 使用纯CSS创建简洁名片卡片的学习实践 在这篇技术博客中&#xff0c;我将分享我的前端学习过程&#xff0c;如何使用纯HTML和CSS创建一个简洁美观的名片式卡片&#xff0c;就像我博客首页展示的那样。这种卡片设计非常适合作为个人简介、产品展示或团队成员介绍…

k8s监控方案实践(一):部署Prometheus与Node Exporter

k8s监控方案实践&#xff08;一&#xff09;&#xff1a;部署Prometheus与Node Exporter 文章目录 k8s监控方案实践&#xff08;一&#xff09;&#xff1a;部署Prometheus与Node Exporter一、Prometheus简介二、PrometheusNode Exporter实战部署1. 创建Namespace&#xff08;p…

谷歌最新推出的Gemini 2.5 Flash人工智能模型因其安全性能相较前代产品出现下滑

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【Python】PDF文件处理(PyPDF2、borb、fitz)

Python提供了多种方法和库用于处理PDF文件&#xff0c;这些工具可以帮助开发者实现诸如读取、写入、合并、拆分以及压缩等功能。以下是几个常用的Python PDF操作库及其基本用法&#xff08;PyPDF2、borb、fitz&#xff09;。 1. PyPDF2 PyPDF2 是一个功能强大的库&#xff0…