设计模式(行为型模式)之:Strategy(策略模式)

news2024/12/23 13:03:06

文章目录

  • 本质:
  • 动机:
  • 定义:
  • 一个不好的例子
  • 策略模式重写
  • 总结

本质:

分离算法,选择实现。

动机:

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

定义:

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展、子类化)

Strategy模式将算法独立于程序流程之外,降低了算法与程序主流程之间的耦合度。

一个不好的例子

将算法硬编入程序主流程段(和程序主流程写在一起),会导致程序难以维护。日后再添加新的算法时,也不利于扩展。
并且,通常我们只想用一部分算法来支持我们的程序,比如提供的99个算法我们只用到2-3个,那么全部编写在一起会造成内存的大量浪费。当然这只是次要问题,主要要解决的,还是降低程序耦合度。
从稳定-变化的角度来分析的话,使用Strategy模式的程序段,算法本身涉及到增删和变化,但算法段之外的流程保持稳定。
代码案例

enum class Sins
{
    MURDER, STEAL, ROBBERY, DEFRAUD
}

void judge(Sins sin)
{
    //判罪前的通用流程
    ...
    
    //处理算法
	if(sin == MURDER)  {...}
    else if(sin == STEAL) {...}
    else if(sin == ROBBERY) {...}
    else if(sin == DEFRAUD) {...}
        
    //判罪后的通用流程
    ...
}

如上所示,这个例子是一个判罪的程序,“算法” 即针对不同的罪行进行相应的处理(判10年,20年,无期之类的,这只是一个示例,因此省去了大部分细节)。

在这个程序段中,为罪行指定刑罚之前和之后的流程是稳定的,比如,判罪前要搜集罪证啊,检察官提起公诉啊,判罪后要登记在案,罪犯可能会上诉啊之类的。而针对罪行的判定是不稳定的,经常会提出一些修正案,增删或变更一些条款。

考虑这种情况,现在我们需要增加一种算法(也就是增加一种罪名),需要做什么呢?我们需要在ENUM中增加罪名,并且在Judge函数中增加相应的处理代码段。显然,代码的复用性并不好,每次对算法的改变都需要重新编译Judge函数。

从设计原则的角度来讲,这种写法违背了开放封闭原则(OCP)(详情可在文章开头 设计模式学习:概述 中了解)。降低了可扩展性。并且,有可能带来debug的问题:每次对算法的改变都有可能在judge函数内部造成Bug。

策略模式重写

那么,现在我们用strategy模式改写一下:

class SinStrategy
{
    virtual void dealSin() = 0;
    virtual ~SinStrategy(){};//C++中基类的析构函数要写成虚的!这里提醒大家。
}

class MurderStrategy : public SinStrategy
{
    //override
    void dealSin() {...}
}

class StealStrategy : public SinStrategy
{
    //override
    void dealSin() {...}
}

class RobberyStrategy : public SinStrategy
{
    //override
    void dealSin() {...}
}

void judge(SinStrategy* sin)
{
    //判罪前的通用流程
    ...
    
    //处理算法,动态绑定
	sin -> dealSin();
        
    //判罪后的通用流程
    ...
}

如上,SinStrategy类作为抽象基类,定义了一个虚函数dealSin,这个函数就是我们要封装的算法。之后的每种罪行只需要重写这一个函数就可以了

而在judge函数中,我们采用动态绑定的方式。程序不知道到底是那种罪名,只需要按规定的流程走完即可。关于SinStrategy具体指向那种子类,就不是我们这个函数操心的问题了。

可以这样调用Judge函数

judge(new StealStrategry());
judge(new MurderStrategry());
judge(new RobberyStrategry());

就实现了对不同罪行的分开处理,而处理罪行的算法也成功的和流程代码段解耦,实现了松耦合。

解释
在strategy模式中,我们把一个特定的算法看作一个对象,因此就可以对它应用多态的思想。

可以这样简单的理解:只要在程序中看到if-else语句或switch语句,就要思考这里需不需要应用Strategy模式——Strategy模式相当于将if-else, switch-case中的模块封装到一个个对象中。至于要不要用Strategy替换If-else/switch,取决于你自己的判断。

Strategy模式也是一个十分常见的设计模式,本质思想和TemPlate Method类似,都是为了遵循开放封闭原则,对某些代码段进行封装,只是对象不同罢了。

总结

设计模式Strategy(策略模式)
稳定点:程序的整体运行框架
变化点:子算法
效果:使得可以独立于主程序增删修改算法
特点:封装算法,重写子过程

UML类图

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

参考一:https://blog.csdn.net/natrick/article/details/113174673
参考二:https://blog.csdn.net/mg2flyingff/article/details/105310045

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

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

相关文章

LeetCode 按摩师 python

目录 1.题目描述 2.普通解法(通过部分测试用例) ​编辑 3.动态规划解法 3.题目总结 1.题目描述 一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻…

(六)CSharp-CSharp图解教程版-委托

一、委托概述 1、什么是委托 委托和类一样,是一种用户定义类型(即是一种类,所以也是一个引用类型)。在它们组成的结构方面区别是,类表示的是数据和方法的集合,而委托则持有一个或多个方法。 可以把 deleg…

Spring架构篇--2.7.1 远程通信基础--Netty原理--NioEventLoopGroup

前言:在使用Netty 时不管是服务端还是客户端都需要 new NioEventLoopGroup 对象进行工作,NioEventLoopGroup的作用是什么呢; 1 NioEventLoopGroup 类图: 从类名字来看它是一个Nio 流的事件轮询器组,既然是一组顾名思…

使用dataFEED OPC Suite将西门子PLC数据转发至阿里云RDS数据库

一 背景 工业现场级别的各种设备会产生大量的数据,这些数据包含生产过程的各种信息,在经过数据库等IT应用的处理后,可为企业提供全面的生产数据分析和决策支持。以往工厂的数据库通常部署在本地,然而得益于云计算的快速发展以及云…

k8s harbor镜像仓库搭建

1.前言 Harbor 是一个开源的云原生镜像仓库,用于存储和分发 Docker 镜像。它提供了一些安全性和管理方面的功能,使得用户可以更好地管理和共享 Docker 镜像 2.配置harbor搭建环境 harbor的搭建需要用到docker、docker-compose服务 docker搭建参考&am…

Vivado 下 IP核之双端口 RAM 读写

目录 Vivado 下 IP核之双端口 RAM 读写 1、RAM IP 核简介 2、实验任务 3、程序设计 3.1、RAM IP 核配置 3.2、顶层模块设计 (1)绘制波形图 4、编写代码 4.1、顶层模块 ip_2port_ram 4.2、RAM 写模块设计 4.3、ram_wr 模块代码 4.4、RAM 读模…

基于graalvm和java swing制作一个文件差异对比的原生应用,附源码

文章目录 1、DFDiff介绍2、软件架构3、安装教程3.1、编译为jar包运行3.2、编译为原生应用运行 4、运行效果图5、项目源码地址 1、DFDiff介绍 当前已实现的功能比较两个文件夹内的文件差异,已支持文件差异对比。 2、软件架构 软件架构说明 开发环境是在OpenJDK17&…

安装 Kafka

文章目录 1.选择操作系统2.配置 Java 环境3.安装 ZooKeeper4.安装 broker(1)安装 broker(2)验证是否安装正确 5.配置 broker(1)常规配置(2)主题的默认配置 6.配置 Kafka 集群&#x…

CAC2.0全新升级发布,为企业邮箱筑起安全壁垒!

5月31日,Coremail举办了【聚焦盗号,企业邮件安全的威胁分析与应对】直播交流会。直播会上Coremail邮件安全团队就邮箱盗号问题进行了深度分享。 面对如此肆虐的盗号现象和即将到来的攻击暴破高峰期,各行业应该如何应对防护邮箱安全呢&#xf…

什么是防火墙?它有什么作用?

作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 一、什么是防火墙 二、防火墙的分类 1、软件防火墙 2、硬件防火墙 三、防火墙的作用 1、防止病毒 2、防止访问不安全内容 3、阻…

如何使用AI帮你制作PPT

一:前言 ChatGPT:智能AI助你畅聊天地 在现代人日益忙碌的生活中,难免需要一些轻松愉快的聊天来放松身心。而现在,有了 ChatGPT,轻松愉快的聊天变得更加智能、有趣且不受时间、地点限制! 什么是 ChatGPT&…

嵌入式Linux系统中SPI 子系统基本实现

1、SPI 驱动源文件目录 Linux common spi driver kernel-4.14/drivers/spi/spi.c Linux 提供的通用接口封装层驱动 kernel-4.14/drivers/spi/spidev.c linux 提供的 SPI 通用设备驱动程序 kernel-4.14/include/linux/spi/spi.h linux 提供的包含 SPI 的主要数据结构和函数…

sourcetree的使用

目录 前言 一、Sourcetree简介 二、创建分支与合并分支 三、合并冲突问题 总结 前言 今天提交项目代码时,接触到非常好用方便的可视化Git管理提交软件Sourcetree,今天记录一下使用过程 一、Sourcetree简介 通过Git可以进行对项目的版本管理,但是如果直接使用Git的软件会比…

MinIO快速入门——在Linux系统上安装和启动

1、简介 MinIO 是一款基于Go语言发开的高性能、分布式的对象存储系统。客户端支持Java,Net,Python,Javacript, Golang语言。MinIO系统,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等。 2、环境搭建&#…

【MySQL】一文带你了解数据库约束

文章目录 1. 约束类型2.PRIMARY KEY:主键约束3.FOREIGN KEY:外键约束4.NOT NULL:非空约束5.UNIQUE:唯一约束5.DEFAULT:默认值约束6.总结 1. 约束类…

用数据说话,R语言有哪七种可视化应用?

今天,随着数据量的不断增加,数据可视化成为将数字变成可用的信息的一个重要方式。R语言提供了一系列的已有函数和可调用的库,通过建立可视化的方式进行数据的呈现。在使用技术的方式实现可视化之前,我们可以先和AI科技评论一起看看…

SpringBoot 源码分析准备应用上下文(2)-prepareContext

一、入口 /*** Run the Spring application, creating and refreshing a new* {link ApplicationContext}.* param args the application arguments (usually passed from a Java main method)* return a running {link ApplicationContext}*/public ConfigurableApplicationC…

生成测试报告,在Unittest框架中就是简单

测试套件(Test Suite)是测试用例、测试套件或两者的集合,用于组装一组要运行的测试(多个测试用例集合在一起)。 (1)创建一个测试套件: import unittest suite unittest.TestSuite…

车载测试:详解ADAS传感器(相机)标定数据采集方法

1.基本原理 相机外参标定,通过拍摄多角度棋盘格标定相机外参。 2.外参标定板设计 标定板分为垂直标定板和水平标定板,由于地面的水平标定板不容易被检测到,本文采用垂直标定板进行相机标定。 在标定过程中标定板需要和车身坐标成正交状态…

中国人民大学与加拿大女王大学金融硕士——所有的为时已晚都是恰逢其时

你是否有过同样的感觉,工作之余想学点什么又觉得有点晚了,心里反复纠结,总是没个结果。记得在网上看到过一句话,你觉得为时已晚的时候,恰恰是最早的时候。与其在心里反复琢磨,不如去付诸行动。中国人民大学…