《设计模式的艺术》笔记 - 策略模式
介绍
策略模式定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为模式。
实现
myclass.h
//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>class Strategy { // 抽象策略类
public:virtual void algorithm() = 0;
};class Context { // 抽象状态类
public:void setStrategy(Strategy *strategy);void algorithm();private:std::shared_ptr<Strategy> m_strategy;
};class ConcreteStrategyA : public Strategy {
public:void algorithm() override;
};class ConcreteStrategyB : public Strategy {
public:void algorithm() override;
};#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>void Context::setStrategy(Strategy *strategy) {m_strategy.reset(strategy);
}void Context::algorithm() {if (m_strategy) {m_strategy->algorithm();} else {std::cout << "当前没有策略" << std::endl;}
}void ConcreteStrategyA::algorithm() {std::cout << "采用策略A" << std::endl;
}void ConcreteStrategyB::algorithm() {std::cout << "采用策略B" << std::endl;
}
main.cpp
#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Strategy *strategyA = new ConcreteStrategyA;Strategy *strategyB = new ConcreteStrategyB;Context *context = new Context;context->setStrategy(strategyA);context->algorithm();context->setStrategy(strategyB);context->algorithm();delete context;return 0;
}
总结
优点
1. 策略模式提供了对开闭原则的完美支持。用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
2. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到抽象策略类中,从而避免重复代码。
3. 策略模式提供了一种可以替换继承关系的办法。如果不使用策略模式,那么使用算法的环境类就可能会有一些子类,每一个子类提供一种不同的算法。但是,这样一来算法的使用就和算法本身混在一起,不符合单一职责原则。决定使用哪一种算法的逻辑和该算法本身混合在一起,从而不可能再独立演化;而且使用继承无法实现算法或行为在程序运行时的动态切换。
4. 使用策略模式可以避免多重条件选择语句。多重条件选择语句不易维护,它把采取哪一种算法或行为的逻辑与算法或行为本身的实现逻辑混合在一起,将它们全部硬编码(Hard Coding)在一个庞大的多重条件选择语句中,比直接继承环境类的办法还要原始和落后。
5. 策略模式提供了一种算法的复用机制。由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。
缺点
1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2. 策略模式将造成系统产生很多具体策略类。任何细小的变化都将导致系统要增加一个新的具体策略类。
3. 无法同时在客户端使用多个策略类。也就是说,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。
适用场景
1. 一个系统需要动态地在几种算法中选择一种。可以将这些算法封装到一个个的具体算法类中,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均具有统一的接口。根据里氏代换原则和面向对象的多态性,客户端可以选择使用任何一个具体算法类,并只需要维持一个数据类型是抽象算法类的对象。
2. 一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句。
3. 不希望客户端知道复杂的、与算法相关的数据结构。在具体策略类中封装算法与相关的数据结构,可以提高算法的保密性与安全性。
练习
myclass.h
//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>class TakeOff { // 起飞抽象策略类
public:virtual void takeOff() = 0; // 起飞
};class Flight { // 飞行抽象策略类
public:virtual void flight() = 0; // 飞行
};class Plane {
public:Plane(TakeOff *takeOff, Flight *flight);virtual ~Plane();virtual void takeOff();virtual void flight();
private:TakeOff *m_takeoff;Flight *m_flight;
};class Simulator { // 模拟系统
public:void setPlane(Plane *plane);void start();private:std::shared_ptr<Plane> m_plane;
};class VerticalTakeOff : public TakeOff { // 垂直起飞策略类
public:void takeOff() override;
};class LongDistanceTakeOff : public TakeOff { // 长距离起飞策略类
public:void takeOff() override;
};class SubSonicFly : public Flight { // 亚音速飞行策略类
public:void flight() override;
};class SuperSonicFly : public Flight { // 超音速飞行策略类
public:void flight() override;
};class Helicopter : public Plane { // 直升机
public:Helicopter();void takeOff() override;void flight() override;
};class AirPlane : public Plane { // 客机
public:AirPlane();void takeOff() override;void flight() override;
};class FighterPlane : public Plane { // 歼击机
public:FighterPlane();void takeOff() override;void flight() override;
};class HarrierPlane : public Plane { // 鹞式战斗机
public:HarrierPlane();void takeOff() override;void flight() override;
};#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>Plane::Plane(TakeOff *takeOff, Flight *flight) {m_takeoff = takeOff;m_flight = flight;
}Plane::~Plane() {if (m_takeoff) {delete m_takeoff;}if (m_flight) {delete m_flight;}
}void Plane::takeOff() {if (m_takeoff) {m_takeoff->takeOff();} else {std::cout << "没有设置起飞特征" << std::endl;}
}void Plane::flight() {if (m_flight) {m_flight->flight();} else {std::cout << "没有设置飞行特征" << std::endl;}
}void Simulator::setPlane(Plane *plane) {m_plane.reset(plane);
}void Simulator::start() {if (m_plane) {m_plane->takeOff();m_plane->flight();} else {std::cout << "请先设置飞机种类" << std::endl;}
}void VerticalTakeOff::takeOff() {std::cout << "垂直起飞" << std::endl;
}void LongDistanceTakeOff::takeOff() {std::cout << "长距离起飞" << std::endl;
}void SubSonicFly::flight() {std::cout << "亚音速飞行" << std::endl;
}void SuperSonicFly::flight() {std::cout << "超音速飞行" << std::endl;
}Helicopter::Helicopter() : Plane(new VerticalTakeOff(), new SubSonicFly()) {}void Helicopter::takeOff() {std::cout << "直升机开始起飞" << std::endl;Plane::takeOff();
}void Helicopter::flight() {std::cout << "直升机开始飞行" << std::endl;Plane::flight();
}AirPlane::AirPlane() : Plane(new LongDistanceTakeOff(), new SubSonicFly()) {}void AirPlane::takeOff() {std::cout << "客机开始起飞" << std::endl;Plane::takeOff();
}void AirPlane::flight() {std::cout << "客机开始飞行" << std::endl;Plane::flight();
}FighterPlane::FighterPlane() : Plane(new LongDistanceTakeOff(), new SuperSonicFly()) {}void FighterPlane::takeOff() {std::cout << "歼击机开始起飞" << std::endl;Plane::takeOff();
}void FighterPlane::flight() {std::cout << "歼击机开始飞行" << std::endl;Plane::flight();
}HarrierPlane::HarrierPlane() : Plane(new VerticalTakeOff(), new SuperSonicFly()) {}void HarrierPlane::takeOff() {std::cout << "鹞式战斗机开始起飞" << std::endl;Plane::takeOff();
}void HarrierPlane::flight() {std::cout << "鹞式战斗机开始飞行" << std::endl;Plane::flight();
}
main.cpp
#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Simulator *simulator = new Simulator();Plane *plane = new Helicopter();simulator->setPlane(plane);simulator->start();std::cout << "----------------------" << std::endl;plane = new AirPlane();simulator->setPlane(plane);simulator->start();std::cout << "----------------------" << std::endl;plane = new FighterPlane();simulator->setPlane(plane);simulator->start();std::cout << "----------------------" << std::endl;plane = new HarrierPlane();simulator->setPlane(plane);simulator->start();delete simulator;return 0;
}
相关文章:
《设计模式的艺术》笔记 - 策略模式
介绍 策略模式定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为模式。 实现 myclass.h // // Created by yuwp on 2024/1/12. //#ifndef DES…...
【Elasticsearch篇】详解使用RestClient操作索引库的相关操作
文章目录 🍔什么是Elasticsearch🌺什么是RestClient🎆代码操作⭐初始化RestClient⭐使用RestClient操作索引库⭐使用RestClient删除索引库⭐使用RestClient判断索引库是否存在 🍔什么是Elasticsearch Elasticsearch是一个开源的分…...
ES数据处理方法
由于日志数据存在ES项目里,需要从ES中获取日志进行分析,使用SQL数据进行处理,如下: select traceid-- STRING COMMENT 流程id, ,appnum -- BIGINT COMMENT 迭代号, ,appversion --STRING COMMENT APP版本, ,appc…...
STM32实现软件IIC协议操作OLED显示屏(2)
时间记录:2024/1/27 一、OLED相关介绍 (1)显示分辨率128*64点阵 (2)IIC作为从机的地址0x78 (3)操作步骤:主机先发送IIC起始信号S,然后发送OLED的地址0x78,然…...
【linux】远程桌面连接到Debian
远程桌面连接到Debian系统,可以使用以下几种工具: 1. VNC (Virtual Network Computing) VNC(Virtual Network Computing)是一种流行的远程桌面解决方案,它使用RFB(Remote Framebuffer Protocol࿰…...
python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-菜单管理实现
锋哥原创的SpringbootLayui python222网站实战: python222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火…...
JS之隐式转换与布尔判定
大家思考一下 [ ] [ ] ? 答案是空字符串 为什么呢? 当做加法运算的时候,发现左右两端存在非原始类型,也就是引用类型对象,就会对对象做隐式类型转换 如何执行的?或者说怎么查找的? 第一步&…...
ubuntu20根目录扩容
ubuntu根目录/ 或者 /home文件夹有时出现空间满了的情况,可以用gparted工具进行空间的重新分配。 首先,如果你是双系统,需要从windows系统下磁盘压缩分配一部分未使用的空间给ubuntu,注意压缩的空间要邻接ubuntu所在盘的位置。 …...
(四)DQL数据查询语言
基础语法 SELECT {*,列名,函数} FROM 表名 [WHERE 条件]; 说明: -SELECT检索关键字 *匹配所有列 , 匹配指定列 -FROM 所提供的数据源(表,视图,另一个查询机制反馈的结果) -WHERE 条件(控制查询的区…...
网络安全03---Nginx 解析漏洞复现
目录 一、准备环境 二、实验开始 2.1上传压缩包并解压 2.2进入目录,开始制作镜像 2.3可能会受之前环境影响,删除即可 编辑 2.4制作成功结果 2.5我们的环境一个nginx一个php 2.6访问漏洞 2.7漏洞触发结果 2.8上传代码不存在漏洞 2.9补充&#…...
第十四届蓝桥杯C组题目 三国游戏
4965. 三国游戏 - AcWing题库 小蓝正在玩一款游戏。 游戏中魏蜀吴三个国家各自拥有一定数量的士兵 X,Y,Z(一开始可以认为都为 00)。 游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i个事件发生时会分…...
【LeetCode-435】无重叠区间(贪心)
题目链接 题目简介 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 示例 1: 输入: [ [1,2], [2,3], [3,4…...
写读后感的时候,可以适当地引用书中的内容吗?
写读后感时,适当地引用书中的内容是可以的,这样可以更好地支持你的观点和感受,增强文章的可信度和说服力。 引用书中的内容可以帮助读者更好地理解你所讨论的主题和人物,同时也可以展示你对原著的深入理解和阅读能力。但是&#…...
RockChip DRM Display Driver
资料来源: 《Rockchip_DRM_Display_Driver_Development_Guide_V1.0.pdf》 《Rockchip_Developer_Guide_DRM_Display_Driver_CN.pdf》 一:DRM概述 DRM(Direct Rendering Manager)直接渲染管理,buffer分配,帧缓冲。对应userspace库位libdrm,libdrm库提供了一系列友好的…...
【数据库】GaussDB数据类型和简单DDL概述
GaussDB是一款华为公司开发的关系型数据库管理系统(RDBMS),提供了多种数据类型用于存储和处理不同类型的数据。以下是GaussDB常见的数据类型: 1、GaussDB常见的数据类型 1.1、数值型(Numeric Types)&…...
malloc/free和new/delete相关问题:
面试题: 1、两种方式的区别: (1)malloc需要强制类型转换,new不需要 (2)malloc需要计算空间大小,new不需要 例如:创建5个int类型的空间 int*p(int *)malloc(sizeof(i…...
设计一套扑克牌
约束和假设 这是一幅用于类似扑克和二十一点等游戏的通用扑克牌吗? 我们可以假设这副牌有52张(2-10,杰克,女王,国王,埃斯)和4种花色吗? 我们可以假设输入是有效的,还是需…...
ubuntu20.04 外接hdmi没有声音
pulseaudio -k 请尝试执行该命令...
Mybatis 拦截器注册方式
在MyBatis中注册拦截器可以通过以下三种方式: 1. XML配置文件方式 在Mybatis的核心配置文件(mybatis-config.xml)中的标签下定义拦截器,并指定实现类。 <configuration><!-- ...其他配置... --><plugins><…...
[嵌入式软件][启蒙篇][仿真平台] STM32F103实现SPI控制OLED屏幕
上一篇: [嵌入式软件][启蒙篇][仿真平台] STM32F103实现LED、按键 [嵌入式软件][启蒙篇][仿真平台] STM32F103实现串口输出输入、ADC采集 [嵌入式软件][启蒙篇][仿真平台]STM32F103实现定时器 [嵌入式软件][启蒙篇][仿真平台] STM32F103实现IIC控制OLED屏幕 文章目…...
【立煌】友达10.1寸G101STN01.C工业液晶屏LCD
G101STN01.C是AUO一款10.1英寸、1024600的工控液晶屏,走LVDS单通道40pin(1ch,6/8-bit),逻辑电压3.3V,公开流通参数里常见亮度500cd/㎡、对比度500:1、视角70/70/60/60、背光WLED且带LEDDriver,背…...
AI 搜索时代,GEO 为何成为企业数字化营销的新标配?
当生成式 AI 全面渗透搜索场景,用户获取信息的方式从 “主动检索筛选” 转向 “AI 精准回答推荐”,传统 SEO 的流量逻辑正在被彻底重构,GEO(AI 搜索生成引擎优化)已然成为企业营销的新赛道。在 AI 搜索成为用户信息获取…...
英飞凌TC3xx SMU模块实战:如何配置看门狗超时自动复位(附寄存器详解)
英飞凌TC3xx SMU模块实战:如何配置看门狗超时自动复位(附寄存器详解) 在汽车电子和工业控制领域,系统稳定性是生死攸关的指标。想象一下,当你的ECU在高速公路上以120km/h运行时突然死机,或者工业机器人正在…...
新手友好:在快马平台通过可交互代码学习OpenClaw Onboard抓取基础
今天想和大家分享一个特别适合机器人领域新手的实践项目——通过InsCode(快马)平台学习OpenClaw Onboard框架的基础操作。作为一个刚接触机械臂控制的小白,我发现这个平台能直接把抽象的控制概念变成可交互的代码,学习效率提升了好几倍。 项目环境搭建零…...
【喜报】义翘神州再获CNAS认可,全面对标2025版药典新标准
义翘神州生物安全检测实验室近日成功通过中国合格评定国家认可委员会(CNAS)的扩项评审及定期监督评审,并已完成全部能力附表更新!这标志着实验室技术能力与质量管理体系持续符合ISO/IEC 17025:2017国际标准的严苛要求,…...
闽北哥-一个人最顶级的能力:复归于朴
一个人最顶级的能力 ——复归于朴**“道家说‘复归于朴’, 儒家说‘赤子之心’, 佛家说‘本自具足’, 鬼谷子说‘知世故而不世故’—— 他们都指向同一种状态: 在红尘中,活出婴儿般的清澈。”🌿 这不是天真…...
硕博必看|论文盲审前,这些硬伤一定要避开!
作为过来人,太懂硕博生面对论文盲审的焦虑——熬夜完成的论文,查重、改格式、找导师签字后,仍怕因细节被盲审专家打回、延毕。盲审专家只看质量不看人情,很多不起眼的小问题,都可能成为“致命扣分点”。今天分享核心干…...
无需安装jupyter notebook,在快马平台5分钟搭建你的第一个数据分析原型
今天想和大家分享一个快速搭建数据分析原型的经验。作为一个经常需要验证想法的数据分析师,最头疼的就是每次换电脑或重装系统后配置Jupyter Notebook环境的过程。最近发现了一个超省心的解决方案,不用本地安装就能直接开搞数据分析。 为什么选择云端Ju…...
OLAP] DuckDB : 开源免费的、面向嵌入式场景、列式存储的分析型数据库
0 序 DuckDB 是近期非常火的一款 AP 数据库,其独特的定位很有趣。甚至有数据库产品考虑将其纳入进来,作为分析能力的扩展。 考虑到项目中一个数据处理场景,就此调研一二。 DuckDB 的爆火,也给所有盲目追逐“大数据”的技术人敲响…...
Pixel Aurora Engine基础教程:Streamlit前端交互逻辑与后端diffusers集成
Pixel Aurora Engine基础教程:Streamlit前端交互逻辑与后端diffusers集成 1. 认识像素极光引擎 Pixel Aurora Engine是一款将AI图像生成与复古游戏美学完美融合的创意工具。它采用Streamlit构建前端界面,后端集成diffusers库实现稳定扩散模型的强大生成…...
