设计模式-策略模式

1. 策略模式

策略模式(Strategy Pattern)针对一组算法,将每一个算法封装到 具有共同接口 的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

在软件开发中,经常会遇到这种情况,开发一个功能可以通过多个算法去实现,比如:代付功能可以选择中金、ChinaPay、全渠道等。我们可以将所有的算法集中在一个类中,在这个类中提供多个方法,每个方法对应一个算法,或者我们也可以将这些算法都封装在一个统一的方法中,使用 if…else… 等条件判断语句进行选择。但是这两种方式都存在 硬编码 的问题,后期需要增加算法就需要修改源代码,这会导致代码的维护变得困难。

策略模式中可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里每一个封装算法的类都可以被称为一种策略,为了保证这些策略在使用时具有一致性,一般会提供一个抽象策略类来做算法的声明。而每种算法对应一个具体策略类

策略模式主要目的是通过定义相似的算法,替换 if else 语句写法,并且可以随时相互替换。当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。

1.1 组成

在这里插入图片描述

  • 抽象策略Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略类(Concrete Strategy):实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境类Context):使用算法的角色,持有一个抽象策略引用,提供给客户端使用。

1.2 示例

使用计算器进行计算的时候,会经常用到加减乘除方法。如果我们想得到两个数字相加的和,我们需要用到“+”符号,得到相减的差,需要用到“-”符号等等。虽然我们可以通过字符串比较使用if/else写成通用方法,但是计算的符号每次增加,我们就不得不加在原先的方法中进行增加相应的代码,如果后续计算方法增加、修改或删除,那么会使后续的维护变得困难。

但是在这些方法中,我们发现其基本方法是固定的,这时我们就可以通过策略模式来进行开发,可以有效避免通过if/else来进行判断,即使后续增加其他的计算规则也可灵活进行调整。

1.2.1 抽象策略

interface CalculateStrategy {int doOperation(int num1, int num2);
}

1.2.2 具体策略类

💗加法:

class OperationAdd implements CalculateStrategy {@Overridepublic int doOperation(int num1, int num2) {return num1 + num2;}
}

💙减法:

class OperationSub implements CalculateStrategy {@Overridepublic int doOperation(int num1, int num2) {return num1 - num2;}
}

💚乘法:

class OperationMul implements CalculateStrategy {@Overridepublic int doOperation(int num1, int num2) {return num1 * num2;}
}

💛除法:

class OperationDiv implements CalculateStrategy {@Overridepublic int doOperation(int num1, int num2) {return num1 / num2;}
}

1.2.3 环境类

定义一个环境角色,提供一个计算的接口供客户端使用。

class  CalculatorContext {// 抽象策略的引用private CalculateStrategy strategy;public CalculatorContext(CalculateStrategy strategy) {this.strategy = strategy;}// 提供一个计算的接口供客户端使用public int executeStrategy(int num1, int num2) {return strategy.doOperation(num1, num2);}
}

1.2.4 测试

public static void main(String[] args) {int a=4,b=2;CalculatorContext context = new CalculatorContext(new OperationAdd());    System.out.println("a + b = " + context.executeStrategy(a, b));context = new CalculatorContext(new OperationSub());      System.out.println("a - b = " + context.executeStrategy(a, b));context = new CalculatorContext(new OperationMul());    System.out.println("a * b = " + context.executeStrategy(a, b));context = new CalculatorContext(new OperationDiv());    System.out.println("a / b = " + context.executeStrategy(a, b));
}

📊输出结果:

a + b = 6
a - b = 2
a * b = 8
a / b = 2

1.3 优缺点

  • 👍优点:
    1. 扩展性好,增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“。
    2. 灵活性好,可以对算法进行自由切换。
    3. 避免使用多重条件选择语句(if else),充分体现面向对象设计思想。
  • 👎缺点:
    1. 使用策略类变多,会增加系统的复杂度。
    2. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

1.4 使用场景

  • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。

    策略模式最大的作用在于分离使用算法的逻辑和算法自身实现的逻辑,这样就意味着当我们想要优化算法自身的实现逻辑时就变得非常便捷,一方面可以采用最新的算法实现逻辑,另一方面可以直接弃用旧算法而采用新算法。使用策略模式能够很方便地进行替换。

  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。

    在实际开发中,有许多算法可以实现某一功能,如查找、排序等,通过 if-else 等条件判断语句来进行选择非常方便。但是这就会带来一个问题:当在这个算法类中封装了大量查找算法时,该类的代码就会变得非常复杂,维护也会突然就变得非常困难。虽然策略模式看上去比较笨重,但实际上在每一次新增策略时都通过新增类来进行隔离,短期虽然不如直接写 if-else 来得效率高,但长期来看,维护单一的简单类耗费的时间其实远远低于维护一个超大的复杂类。

  • 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。

    如果我们不希望客户知道复杂的、与算法相关的数据结构,在具体策略类中封装算法与相关数据结构,可以提高算法的保密性与安全性。

1.5 模板方法模式和策略模式区别

这两种模式在 Spring 中都广泛存在,例如大家所熟知的 Spring Data 模块,存在 JDBCTemplateRedisTemplateMongoTemplate 等均是典型的 模板模式。而例如 Spring MVC 中各种处理 handler,则是典型的 策略模式。两者有什么区别呢?

  • 模板方法模式 一般只针对一套算法,注重对同一个算法的不同细节进行抽象提供不同的实现。而 策略模式 注重多套算法多套实现,替换 if else 语句写法,并且可以随时替换算法

参考文章:
📖 策略模式和模板方法模式
📖 JAVA设计模式之策略模式详解

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

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

相关文章

FFmpeg 4.3 音视频-多路H265监控录放C++开发十四,总结编码过程,从摄像头获得数据后,转成AVFrame,然后再次转成AVPacket,

也就是将摄像头采集到的YUV 的数据换成 AVFrame,然后再次转成 AVPacket,那么这AVPakcet数据要怎么办呢?分为三种情况: 一种是将AVPacket存储成h264文件,由于h264编码器在将avframe变成avpacket的时候就是按照h264的格…

【srm,招标询价】采购电子化全流程,供应商准入审核,在线询价流程管理(JAVA+Vue+mysql)

前言: 随着互联网和数字技术的不断发展,企业采购管理逐渐走向数字化和智能化。数字化采购平台作为企业采购管理的新模式,能够提高采购效率、降低采购成本、优化供应商合作效率,已成为企业实现效益提升的关键手段。系统获取在文末…

Transformer学习笔记(一)

Transformer学习笔记 基于 3B1B 可视化视频 自注意力机制 1.每个词的初始嵌入是一个高维向量,只编码该单词含义,与上下文没有关联 2.对初始向量进行位置编码,在高维向量中编码进位置信息(单词在语言序列中的位置信息&#xff…

4.4.5 timer中断流向Linux(从interrupt log回放)

4.4.5 timer中断流向Linux(从interrupt log回放) 按上文所述,timer中断3已经记录到root domain的interrupt log。在《3.4.1.3 IPIPE interrupt log数据结构》中,已经讨论过interrupt log的记录与回放。本小结,讨论什么…

WinDefender Weaker

PPL Windows Vista / Server 2008引入 了受保护进程的概念,其目的不是保护您的数据或凭据。其最初目标是保护媒体内容并符合DRM (数字版权管理)要求。Microsoft开发了此机制,以便您的媒体播放器可以读取例如蓝光,同时…

基于redis完成延迟队列

添加依赖 使用redisson完成延迟队列效果 <!-- redisson依赖 --><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.17.4</version> <!-- 请使用最新版本 --></dependency&g…

星辰资讯 | TiDB v7.5.4 v8.4.0 发版

作者&#xff1a; ShawnYan 原文来源&#xff1a; https://tidb.net/blog/6e299751 TiDB 8.4.0 DMR 发版 11 月 11 日&#xff0c;TiDB 8.4.0 版本发布&#xff0c;以下是该版本的一些关键特性和改进&#xff1a; 性能 分区表全局索引成为正式功能 &#xff1a;提高检索…

Spring基础

Spring基础 目录&#xff1a; 一、Spring框架简介 二、Spring容器机制 一、Spring框架简介 1. Spring发展历程 •在Spring兴起之前&#xff0c;Java企业级开发主要通过EJB (Enterprise JavaBean)完成。EJB是服务器端的组件模型&#xff0c;由于它过于依靠EJB容器&#xf…

二分查找法(leetcode 704)

在一个数组里找一个target&#xff0c;判断这个target在不在这个数组里&#xff0c;如果在&#xff0c;返回这个数组所对应的这个元素所对应的下标&#xff0c;否则返回-1. 易错点&#xff1a; &#xff08;1&#xff09;while(left<right) vs while(left<…

python的matplotlib实现数据分析绘图

目录 需求 效果 数据分析绘图示例 代码解释 运行结果 需求 分析一个班级中学生成绩分布&#xff0c;并绘图 效果 数据分析绘图示例 import matplotlib.pyplot as plt import numpy as np# 假设的学生成绩数据 np.random.seed(0) # 设置随机种子以确保结果可复现 score…

STM32电源管理—实现低功耗

注&#xff1a; 本文是学习野火的指南针开发板过程的学习笔记&#xff0c;可能有误&#xff0c;详细请看B站野火官方配套视频教程&#xff08;这个教程真的讲的很详细&#xff0c;请给官方三连吧&#xff09; 在响应绿色发展的同时&#xff0c;在很多应用场合中都对电子设备的功…

[JAVA]MyBatis框架—如何获取SqlSession对象实现数据交互(基础篇)

假设我们要查询数据库的用户信息&#xff0c;在MyBatis框架中&#xff0c;首先需要通过SqlSessionFactory创建SqlSession&#xff0c;然后才能使用SqlSession获取对应的Mapper接口&#xff0c;进而执行查询操作 在前一章我们学习了如何创建MyBatis的配置文件mybatis.config.xm…

【视频讲解】Python深度神经网络DNNs-K-Means(K-均值)聚类方法在MNIST等数据可视化对比分析...

全文链接&#xff1a;https://tecdat.cn/?p38289 分析师&#xff1a;Cucu Sun 近年来&#xff0c;由于诸如自动编码器等深度神经网络&#xff08;DNN&#xff09;的高表示能力&#xff0c;深度聚类方法发展迅速。其核心思想是表示学习和聚类可以相互促进&#xff1a;好的表示会…

Java 网络编程(二)—— TCP流套接字编程

TCP 和 UDP 的区别 在传输层&#xff0c;TCP 协议是有连接的&#xff0c;可靠传输&#xff0c;面向字节流&#xff0c;全双工 而UDP 协议是无连接的&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工 有连接和无连接的区别是在进行网络通信的时候&#xff0c;…

机器学习—正则化和偏差或方差

正则化参数的选择对偏差和方差的影响 用一个四阶多项式&#xff0c;要用正则化拟合这个模型&#xff0c;这里的lambda的值是正则化参数&#xff0c;它控制着你交易的金额&#xff0c;保持参数w与训练数据拟合&#xff0c;从将lambda设置为非常大的值的示例开始&#xff0c;例如…

【笔记】企业架构TOGAF 10的架构从4A增加至6A

背景 谈谈学习TOGAF 10的总结和笔记&#xff0c;说说较9.2版本有哪些变化。最直观的当属从原来的4A架构升级到6A架构&#xff0c;单独从原来的4A中提炼形成了安全架构、系统架构两个概念&#xff0c;谈谈理解并回顾总结一下学习笔记。 TOGAF 10 将安全架构单独列为一种架构&…

AI写作(十)发展趋势与展望(10/10)

一、AI 写作的崛起之势 在当今科技飞速发展的时代&#xff0c;AI 写作如同一颗耀眼的新星&#xff0c;迅速崛起并在多个领域展现出强大的力量。 随着人工智能技术的不断进步&#xff0c;AI 写作在内容创作领域发挥着越来越重要的作用。据统计&#xff0c;目前已有众多企业开始…

【模块一】kubernetes容器编排进阶实战之资源管理核心概念

kubernetes 资源管理核心概念 k8s的设计理念—分层架构 CRI-container runtime interface-容器运行接口 CNI-container network interface-容器网络接口 CSI-container storage interface-容器存储接口 k8s的设计理念—API设计原则 https://www.kubernetes.org.cn/kubernete…

DBeaver中PostgreSQL数据库显示不全的解决方法

本文介绍在DBeaver中&#xff0c;连接PostgreSQL后&#xff0c;数据库显示不全的解决方法。 最近&#xff0c;在DBeaver中连接了本地的PostgreSQL数据库。但是连接后打开这个数据库时发现&#xff0c;其所显示的Databases不全。如下图所示&#xff0c;Databases只显示了一个pos…

ElasticSearch学习笔记二:使用Java客户端

一、前言 在上一篇文章中&#xff0c;我们对ES有了最基本的认识&#xff0c;本着实用为主的原则&#xff0c;我们先不学很深的东西&#xff0c;今天打算先学习一下ES的Java客户端如何使用。 二、创建项目 1、普通Maven项目 1、创建一个Maven项目 2、Pom文件 <dependenc…