【第14节】C++设计模式(行为模式)-Strategy (策略)模式
一、问题的提出
Strategy 模式:算法实现与抽象接口的解耦
Strategy 模式和 Template 模式要解决的问题是相似的,都是为了将业务逻辑(算法)的具体实现与抽象接口解耦。Strategy 模式通过将算法封装到一个类(Context)中,并通过组合的方式将具体算法的实现委托给组合对象来完成。
二、模式选择
Strategy 模式的典型结构如下图所示:
其核心思想是将算法的逻辑抽象接口(如 `DoAction`)封装到一个类中(Context),然后通过委托的方式将具体的算法实现交给具体的 Strategy 类(如 `ConcreteStrategyA` 和 `ConcreteStrategyB`)来完成。
三、代码实现
以下是 Strategy 模式的完整实现代码,采用 C++ 编写。
代码实现
Strategy.h
#ifndef _STRATEGY_H_
#define _STRATEGY_H_// 抽象策略类,定义算法接口
class Strategy {
public:Strategy() {}virtual ~Strategy() {}virtual void AlgorithmInterface() = 0; // 算法接口,子类实现
};// 具体策略类A,实现算法接口
class ConcreteStrategyA : public Strategy {
public:ConcreteStrategyA() {}virtual ~ConcreteStrategyA() {}void AlgorithmInterface() override; // 实现算法接口
};// 具体策略类B,实现算法接口
class ConcreteStrategyB : public Strategy {
public:ConcreteStrategyB() {}virtual ~ConcreteStrategyB() {}void AlgorithmInterface() override; // 实现算法接口
};#endif //~_STRATEGY_H_
Strategy.cpp
#include "Strategy.h"
#include <iostream>
using namespace std;// 具体策略类A的算法实现
void ConcreteStrategyA::AlgorithmInterface() {cout << "ConcreteStrategyA: AlgorithmInterface" << endl;
}// 具体策略类B的算法实现
void ConcreteStrategyB::AlgorithmInterface() {cout << "ConcreteStrategyB: AlgorithmInterface" << endl;
}
Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_class Strategy;/*** Context 类是 Strategy 模式的关键,也是 Strategy 模式和 Template 模式的主要区别所在。* Strategy 模式通过组合(委托)的方式实现算法的异构,而 Template 模式则通过继承的方式实现。*/
class Context {
public:Context(Strategy* strategy); // 构造函数,传入具体策略~Context();void DoAction(); // 执行策略
private:Strategy* _strategy; // 组合的策略对象
};#endif //~_CONTEXT_H_
Context.cpp
#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;// 构造函数,初始化策略对象
Context::Context(Strategy* strategy) : _strategy(strategy) {}// 析构函数,释放策略对象
Context::~Context() {if (_strategy) {delete _strategy;}
}// 执行策略
void Context::DoAction() {_strategy->AlgorithmInterface();
}
main.cpp
#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;int main(int argc, char* argv[]) {Strategy* strategyA = new ConcreteStrategyA(); // 创建具体策略AContext* contextA = new Context(strategyA); // 创建上下文,传入策略AcontextA->DoAction(); // 执行策略AStrategy* strategyB = new ConcreteStrategyB(); // 创建具体策略BContext* contextB = new Context(strategyB); // 创建上下文,传入策略BcontextB->DoAction(); // 执行策略Bdelete contextA;delete contextB;return 0;
}
代码说明
Strategy 模式的实现非常直观,其核心思想是将算法的逻辑封装到一个类中,并通过组合的方式将具体算法的实现委托给组合对象。Context 类通过持有 Strategy 对象的指针,动态调用具体的算法实现。
四、总结讨论
Strategy 模式和 Template 模式解决了类似的问题,但它们采用了不同的实现方式:Strategy 模式通过组合(委托)实现算法的异构,而 Template 模式则通过继承实现。这两种方式各有优缺点:
继承的优缺点
优点:
(1)易于修改和扩展被复用的实现。
缺点:
(1)破坏了封装性,父类的实现细节暴露给子类;
(2)属于“白盒”复用;
(3)当父类的实现更改时,所有子类都需要随之改变;
(4)继承的实现在运行期间不能改变(编译期间已确定)。
组合的优缺点
优点:
(1)属于“黑盒”复用,被包含对象的内部细节对外不可见;
(2)封装性好;
(3)实现和抽象的依赖性小;
(4)可以在运行期间动态定义实现(通过抽象基类的指针)。
缺点:
(1)系统中对象可能过多。
从上述对比可以看出,组合相比继承具有更好的灵活性和封装性。因此,在面向对象设计中,有一条重要的原则:优先使用对象组合,而非类继承(Favor Composition Over Inheritance)。
Strategy 模式通过组合的方式实现了算法与抽象接口的解耦,适用于需要在运行时动态切换算法的场景。与 Template 模式相比,Strategy 模式更加灵活,避免了继承带来的强耦合性。在实际开发中,优先使用组合而非继承,可以显著提高代码的可维护性和扩展性。
相关文章:

【第14节】C++设计模式(行为模式)-Strategy (策略)模式
一、问题的提出 Strategy 模式:算法实现与抽象接口的解耦 Strategy 模式和 Template 模式要解决的问题是相似的,都是为了将业务逻辑(算法)的具体实现与抽象接口解耦。Strategy 模式通过将算法封装到一个类(Context&am…...
播放器系列4——PCM重采样
FFmpeg重采样过程 #mermaid-svg-QydNPsDAlg9lTn6z {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QydNPsDAlg9lTn6z .error-icon{fill:#552222;}#mermaid-svg-QydNPsDAlg9lTn6z .error-text{fill:#552222;stroke:#5…...

网络安全需要学多久才能入门?
网络安全是一个复杂且不断发展的领域,想要入行该领域,我们需要付出足够多的时间和精力好好学习相关知识,才可以获得一份不错的工作,那么网络安全需要学多久才能入门?我们通过这篇文章来了解一下。 学习网络安全的入门时间因个人的…...
通俗版解释:分布式和微服务就像开餐厅
一、分布式系统:把大厨房拆成多个小厨房 想象你开了一家超火爆的餐厅,但原来的厨房太小了: 问题:一个厨师要同时切菜、炒菜、烤面包,手忙脚乱还容易出错。 解决方案: 拆分成多个小厨房(分布式…...

JAVA安全—手搓内存马
前言 最近在学这个内存马,就做一个记录,说实话这个内存马还是有点难度的。 什么是内存马 首先什么是内存马呢,顾名思义就是把木马打进内存中。传统的webshell一旦把文件删除就断开连接了,而Java内存马则不同,它将恶…...

【神经网络】python实现神经网络(一)——数据集获取
一.概述 在文章【机器学习】一个例子带你了解神经网络是什么中,我们大致了解神经网络的正向信息传导、反向传导以及学习过程的大致流程,现在我们正式开始进行代码的实现,首先我们来实现第一步的运算过程模拟讲解:正向传导。本次代…...
历年湖南大学计算机复试上机真题
历年湖南大学计算机复试机试真题 在线评测:https://app2098.acapp.acwing.com.cn/ 杨辉三角形 题目描述 提到杨辉三角形。 大家应该都很熟悉。 这是我国宋朝数学家杨辉在公元 1261 年著书《详解九章算法》提出的。 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 …...

[LeetCode]day33 150.逆波兰式求表达值 + 239.滑动窗口最大值
逆波兰式求表达值 题目链接 题目描述 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意: 有效的算符为 ‘’、‘-’、‘*’ 和 ‘/’ 。 每个操作数(运…...

【银河麒麟高级服务器操作系统实际案例分享】数据库资源重启现象分析及处理全过程
更多银河麒麟操作系统产品及技术讨论,欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer…...
C#中泛型的协变和逆变
协变: 在泛型接口中,使用out关键字可以声明协变。这意味着接口的泛型参数只能作为返回类型出现,而不能作为方法的参数类型。 示例:泛型接口中的协变 假设我们有一个基类Animal和一个派生类Dog: csharp复制 public…...
【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-附录B-严格模式
附录B、严格模式 严格模式 ECMAScript 5 首次引入严格模式的概念。严格模式用于选择以更严格的条件检查 JavaScript 代码错误,可以应用到全局,也可以应用到函数内部。严格模式的好处是可以提早发现错误,因此可以捕获某些 ECMAScript 问题导致…...
跨平台 C++ 程序崩溃调试与 Dump 文件分析
前言 C 程序在运行时可能会由于 空指针访问、数组越界、非法内存访问、栈溢出 等原因崩溃。为了分析崩溃原因,我们通常会生成 Dump 文件(Windows 的 .dmp,Linux 的 core,macOS 的 .crash),然后用调试工具分…...
缺陷VS质量:为何软件缺陷是质量属性的致命对立面?
为何说缺陷是质量的对立面? 核心逻辑:软件质量的定义是“满足用户需求的程度”,而缺陷会直接破坏这种满足关系。 对立性:缺陷的存在意味着软件偏离了预期行为(如功能错误、性能不足、安全性漏洞等)&#…...
伍[5],伺服电机,电流环,速度环,位置环
电流环、速度环和位置环是电机控制系统中常见的三个闭环控制环节,通常采用嵌套结构(内环→外环:电流环→速度环→位置环),各自负责不同层级的控制目标。以下是它们的详细说明及相互关系: 1. 电流环(最内环) 作用:控制电机的电流,间接控制输出转矩(τ=Kt⋅Iτ=Kt⋅…...

RuntimeError: CUDA error: device-side assert triggered
RuntimeError: CUDA error: device-side assert triggered 欢迎来到英杰社区,这里是博主英杰https://bbs.csdn.net/topics/617804998 原因: cuda运行可能是异步的(asynchronously),因此报错信息中提示的位置可能不准确…...
清华大学Deepseek第六版AIGC发展研究3.0(共186页,附PDF下载)
人工智能生成内容(AIGC)正以前所未有的速度改变我们的生活。 2024年底,清华大学新闻与传播学院与人工智能学院联合发布了《AIGC发展研究3.0版》,这份报告系统梳理了AIGC技术的突破性进展、应用场景及社会影响,并展望了…...
SpringBoot生成唯一ID的方式
1.为什么要生成唯一ID? 数据唯一性:每个记录都需要有一个独一无二的标识符来确保数据的唯一性。这可以避免重复的数据行,并有助于准确地查询、更新或删除特定的记录。 数据完整性:通过使用唯一ID,可以保证数据库中的数…...
通俗易懂的分类算法之K近邻详解
通俗易懂的分类算法之K近邻详解 用最通俗的语言和例子,来彻底理解 K近邻(K-Nearest Neighbors,简称 KNN) 这个分类算法。不用担心复杂的数学公式,我会用生活中的例子来解释,保证你一听就懂! 1.…...
CSDN markdown 操作指令等
CSDN markdown 操作指令等 页内跳转 [内容](#1) <div id"1"> </div>...
【linux】文件与目录命令 - uniq
文章目录 1. 基本用法2. 常用参数3. 用法举例4. 注意事项 uniq 命令用于过滤文本文件中相邻的重复行,并支持统计重复次数或仅保留唯一行。它通常与 sort 命令配合使用,因为 uniq 只识别相邻的重复行。 1. 基本用法 语法: uniq [选项] [输入…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...

aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...