【第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 [选项] [输入…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...

GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...