信阳市工程建设信息网站/关键词检测
前言
什么是策略模式?
策略模式(Strategy Pattern)是一种面向对象设计模式,它定义了算法族(一组相似的算法),并且将每个算法都封装起来,使得它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。
在策略模式中,定义一个抽象的策略接口或者抽象类来封装不同的具体算法实现,并由客户端根据需要动态选择使用哪种算法。这种方式支持应用程序灵活地更换算法和扩展算法,而无需修改已有代码。此外,策略模式可以减少大量的 if-else 语句,提高代码的可读性和可维护性。
策略模式通常包含三个角色:
环境(Context)角色:通过一个持有某个策略实例的变量来调用具体的策略算法。
抽象策略(Strategy)角色:定义了一个公共的接口或抽象类,规定了所有具体策略角色必须实现的方法。
具体策略(Concrete Strategy)角色:实现了抽象策略接口或抽象类中定义的方法,提供具体的处理逻辑。每个具体策略角色都代表一个算法的具体实现。
在使用策略模式时,首先定义一个抽象的策略接口或抽象类,然后定义具体的策略实现类,最后将策略实现类注入到需要使用的类中。这样可以让客户端通过改变具体的策略实现类,来灵活地选择不同的算法,从而实现目标。
一、开始学习
本次案例,通过支付的例子来完成一个案例。
1、新建项目,结构如下
2、添加 spring 依赖
<!-- spring 的核心依赖 --><dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.23</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.5</version></dependency></dependencies>
3、在 service 包下新建一个 Payment 接口,在 impl 包下新建 AliPayment、WeChartPayment实现类
Payment 接口
/*** @Date 2023-10-07* @Author qiu* 支付接口,对应有不同的实现*/
public interface Payment {/*** 支付方法* @param money*/void pay(BigDecimal money);}
Alipayment 实现类
/*** @Date 2023-10-07* @Author qiu* 支付宝支付*/
@Service
@Slf4j
public class AliPayment implements Payment {@Overridepublic void pay(BigDecimal money) {log.info("使用支付宝支付金额: " + money.doubleValue());}
}
WeChartPayment 实现类
/*** @Date 2023-10-07* @Author qiu* 微信支付*/
@Slf4j
@Service
public class WeChartPayment implements Payment {@Overridepublic void pay(BigDecimal money) {log.info("使用微信支付金额:" + money.doubleValue());}
}
看下图分析:
在策略模式中,定义一个抽象的策略接口或者抽象类来封装不同的具体算法实现,并由客户端根据需要动态选择使用哪种算法。
现在大家可以理解这句话的意思了吧,我把支付的方法抽象出来,定义一个接口,但是具体的实现交给了实现它的实现类去完成,每一种实现都是独立的,如果现在需要新增一个支付方式该怎么办呢?很简单,只需要再新增一个实现类去继承 Payment 支付接口即可,具体的实现也是这个实现类去完成,把每个不同类型的支付方式都分别交给独立的实现类去完成,交给用户去选择。这样写代码也更加方便维护,使用微信支付出现问题时我们只需要去修改 WeChartPayment 实现类的代码,不需要改动其他的实现类的代码,而且修改 WeChartPayment 的代码也不会影响到其他实现类的正常运行,这就是策略模式。
4、如何使用 spring 注入所有的实现类呢?
1)新增一个 PaymentContext 类
@Service
/*** 利用 Lombok 生成一个带参数的构造方法* 这样即可以通过构造方法直接注入*/
@RequiredArgsConstructor
public class PaymentContext {/*** 构造方法注入* 注入一个 map 集合,spring 会将 Payment 接口的所有实现类* 一并保存到 map 中* key(bean 的 id) 为支付类型, value 是具体的支付策略实现*/private final Map<String, Payment> paymentMap;/*** 根据支付类型选择具体的策略来完成支付* @param paymentType 支付类型* @param money 支付金额*/public void pay(String paymentType, BigDecimal money){Payment payment = paymentMap.get(paymentType);payment.pay(money);}}
这是一个策略上下文类
PaymentContext
,它使用了构造方法注入来获取支付策略的集合。注解
@Service
表明该类是一个服务类,用于处理业务逻辑。注解
@RequiredArgsConstructor
是 Lombok 提供的注解,它会生成一个带有final
字段的构造函数。在这个类中,通过构造方法注入了一个Map<String, Payment>
类型的成员变量paymentMap
。Spring 会将所有实现了Payment
接口的 bean 注册到这个paymentMap
中,key 为 bean 的 id,value 为相应的具体支付策略实现。在
pay
方法中,通过传入的paymentType
参数从paymentMap
中获取对应的具体支付策略,并调用其pay
方法来完成支付操作。通过这种方式,可以在策略上下文中动态选择具体的支付策略进行支付。通过构造方法注入支付策略的集合,可以方便地扩展和管理不同支付类型的策略。
2)在 controller 包下新增一个 PaymentContorller 类
@Controller
@RequiredArgsConstructor
public class PaymentController {/*** 注入策略上下文*/private final PaymentContext context;public void pay(String type, BigDecimal money) {context.pay(type, money);}}
这是一个支付控制器类
PaymentController
,它使用了策略模式来处理不同类型的支付。注解
@Controller
表明该类是一个控制器,用于接收和处理请求。注解
@RequiredArgsConstructor
是 Lombok 提供的注解,它会生成一个包含所有final
和@NonNull
注解的字段的构造函数。控制器类中声明了一个名为
context
的PaymentContext
类型的成员变量,用于存储策略上下文对象。在
pay
方法中,根据传入的type
和money
参数,调用context
的pay
方法来执行具体的支付逻辑。这里的pay
方法是策略上下文对象中定义的方法,用于根据支付类型调用相应的具体支付策略。通过这种方式,可以将不同类型的支付逻辑封装到不同的具体支付策略中,并通过策略上下文来选择并执行相应的支付策略。这样可以实现支付方式的灵活切换和扩展。
5、在 resources 下新建一个 spring 的 xml 文件 beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 启用包扫描 --><context:component-scan base-package="edu.nf.ch09"/></beans>
6、测试
public class Main {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");PaymentContext bean = context.getBean(PaymentContext.class);bean.pay("weChartPayment", new BigDecimal("100"));}}
运行结果
这是一个启动类
Main
,它通过 Spring 容器来获取支付上下文对象,并调用其pay
方法进行支付操作。在
main
方法中,利用ClassPathXmlApplicationContext
类加载 classpath 下的beans.xml
文件,从而创建一个 Spring 容器。使用容器的
getBean
方法获取 id 为paymentContext
的 bean 对象,即上下文对象PaymentContext
。最后,通过调用上下文对象的
pay
方法来完成支付操作。这里传入的第一个参数是支付类型,在beans.xml
中扫描的 bean id 即为对应的支付类型;第二个参数为支付金额。在运行动图中可以看到,我们需要使用哪种支付方式就把它的 bean id写进去即可。
通过 Spring 容器的支持,我们可以方便地管理和维护各个支付类型的具体支付策略,同时也能够方便地进行扩展和配置。
二、使用策略模式注入所有实现类的好处
使用策略模式注入所有实现类的好处主要有以下几个方面:
解耦性:通过策略模式,将具体的实现类与调用它们的类解耦。调用方只需要依赖于抽象的策略接口或基类,而不需要关心具体的实现类。这样可以降低类之间的耦合度,并且使得系统更加灵活和可维护。
可扩展性:当新增一种支付类型时,只需实现相应的支付策略,并注册到容器中即可,无需修改调用方的代码。通过容器自动注入所有实现类,实现类的新增和移除变得方便快捷,可以根据业务需求随时扩展支付策略。
可配置性:通过注入所有实现类,可以将不同的实现类配置到容器的配置文件中,而不需要修改源代码。这样在不同的环境中,可以通过简单的配置文件修改支付策略的选择,而无需重新编译和部署代码。
单一职责原则:通过策略模式,每个具体的支付策略类只需要关注自身特定的支付逻辑,符合单一职责原则。这样可以提高代码的可读性、可维护性和可测试性。
总之,使用策略模式注入所有实现类具有解耦性、可扩展性、可配置性和单一职责原则等优点,使得系统更加灵活、可维护和可测试。
三、gitee 案例
案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git
相关文章:

Spring framework Day11:策略模式中注入所有实现类
前言 什么是策略模式? 策略模式(Strategy Pattern)是一种面向对象设计模式,它定义了算法族(一组相似的算法),并且将每个算法都封装起来,使得它们可以互相替换。策略模式让算法的变…...

MBBF展示的奇迹绿洲:5G的过去、此刻与未来
如果你来迪拜,一定不会错过全世界面积最大的人工岛项目,这是被称为世界第八大奇迹的棕榈岛。多年以来,这座岛从一片砂石、一棵棕榈树开始,逐步建成了整个波斯湾地区的地标,吸引着全世界游人的脚步。 纵观整个移动通信发…...

加持智慧医疗,美格智能5G数传+智能模组让就医触手可及
智慧医疗将云计算、物联网、大数据、AI等新兴技术融合赋能医疗健康领域,是提高医疗健康服务的资源利用效率,创造高质量健康医疗的新途径。《健康中国2030规划纲要》把医疗健康提升到了国家战略层面,之后《“十四五”全面医疗保障规划》等一系…...

Stm32_标准库_14_串口蓝牙模块_手机与蓝牙模块通信_实现模块读取并修改信息
由手机向蓝牙模块传输时间信息,Stm32获取信息并将已存在信息修改为传入信息 测试代码: #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Serial.h"uint16_t num…...

UDP 的报文结构
UDP的报文结构: 其中前面的源端口号和目的端口号,UDP长度和UDP检验和,它们都是2个字节。 那么什么是UDP长度呢,它指的是后面的数据的长度,换算单位也就是64kb,因此一个数据报(数据)最…...

torch.hub.load报错urllib.error.HTTPError: HTTP Error 403: rate limit exceeded
在运行DINOv2的示例代码时,需要载入预训练的模型,比如: backbone_model torch.hub.load(repo_or_dir"facebookresearch/dinov2", modelbackbone_name) torch.hub.load报错“urllib.error.HTTPError: HTTP Error 403: rate limit…...

测试左移右移-理论篇
目录 前言一、浅解左移1.什么是测试左移?1.1对产品1.2对开发1.3对测试1.4对运维 二、浅解右移1.1对产品1.2对开发1.3对测试1.4对运维 三、总结 前言 测试左移右移,很多人说能让测试更拥有主动权,展示出测试岗位也是有很大的价值,…...

【TensorFlow2 之015】 在 TF 2.0 中实现 AlexNet
一、说明 在这篇文章中,我们将展示如何在 TensorFlow 2.0 中实现基本的卷积神经网络 \(AlexNet\)。AlexNet 架构由 Alex Krizhevsky 设计,并与 Ilya Sutskever 和 Geoffrey Hinton 一起发布。并获得Image Net2012竞赛中冠军。 教程概述: 理论…...

Python进阶之迭代器
文章目录 前言一、迭代器介绍及作用1.可迭代对象2. 迭代器 二、常用函数和迭代器1.常用函数2.迭代器 三、总结结束语 💂 个人主页:风间琉璃🤟 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主💬 如果文章对你有帮助、欢迎关注…...

Vue鼠标右键画矩形和Ctrl按键多选组件
效果图 说明 下面会贴出组件代码以及一个Demo,上面的效果图即为Demo的效果,建议直接将两份代码拷贝到自己的开发环境直接运行调试。 组件代码 <template><!-- 鼠标画矩形选择对象 --><div class"objects" ref"objectsR…...

【MySQL JDBC】使用Java连接MySQL数据库
一、什么是JDBC? 理解API的概念 API:Application Programing Interface -- 应用程序编程接口写好一个程序,这个程序需要给别人提供哪些功能?这些功能就是通过一些 函数/类 这样的方式来提供的。例如 Random、Scanner、ArrayList..…...

字节码学习之常见java语句的底层原理
文章目录 前言1. if语句字节码的解析 2. for循环字节码的解析 3. while循环4. switch语句5. try-catch语句6. i 和i的字节码7. try-catch-finally8. 参考文档 前言 上一章我们聊了《JVM字节码指令详解》 。本章我们学以致用,聊一下我们常见的一些java语句的特性底层…...

Godot C#连接信号不能像GDScirpt一样自动添加代码
前言 我网上找了好久,发现Godot 对于C# 的支持还有待增强 使用c#脚本有办法像gds那样连接节点自带信号时自动生成信号吗? 百度贴吧 Godot C# How To, Episode 9. Signals With Parameters | Godot Mono 解决方案 把信号拉长,看他的属性 修…...

快速自动化处理JavaScript渲染页面
在进行网络数据抓取时,许多网站使用了JavaScript来动态加载内容,这给传统的网络爬虫带来了一定的挑战。本文将介绍如何使用Selenium和ChromeDriver来实现自动化处理JavaScript渲染页面,并实现有效的数据抓取。 1、Selenium和ChromeDriver简介…...

通过API接口进行商品价格监控,可以按照以下步骤进行操作
要实现通过API接口进行商品价格监控,可以按照以下步骤进行操作: 申请平台账号并选择API接口:根据需要的功能,选择相应的API接口,例如商品API接口、店铺API接口、订单API接口等,这一步骤通常需要我们在相应…...

(vue3)大事记管理系统 文章管理页
[element-plus进阶] 文章列表渲染(带搜索&到分页) 表单架设:当前el-form标签配置一个inline属性,里面的元素就会在一行显示了 中英国际化处理:App.vue中el-config-provider标签包裹组件,意味着整个组…...

springboot 使用RocketMQ客户端生产消费消息DEMO
创建springboot项目省略 项目依赖 注意:当前客户端版本是 5.1.3 ,安装的rocketmq服务的版本要与其对应 <properties><java.version>11</java.version><rocketmq-client-java-version>5.1.3</rocketmq-client-java-version&…...

第三章 内存管理 四、连续分配管理方式
目录 一、内存空间的分配与回收 1、连续分配管理方式 (1)、单一连续分配 优点: 缺点: (2)、固定分区分配 分区大小相等: 分区大小不等: (3)、动态分区…...

npm install报--4048错误和ERR_SOCKET_TIMEOUT问题解决方法之一
一、问题描述 学习vue数字大屏加载动漫效果时,在项目终端页面输入全局下载指令 npm install -g json-server 问题1、报--4048错误 会报如下错误 operation not permitted......errno: -4048code:EPERMsyscall: mkdir......The operation was reiected by your op…...

合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意:最终,合并后数组…...

自动泊车系统设计学习笔记
1 概述 1.1 自动泊车系统研究现状 目前对于自动泊车系统的研究方法通常有两种实现方式: 整个泊车操作可以分为四个阶段:第一阶段车辆向前行驶进行车位识别,第二阶段车辆行驶到准备泊车时的待泊车区域,第三阶段车辆按照规划好的…...

基于Java的家电销售网站管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域…...

设计模式~备忘录模式(memento)-22
目录 (1)优点: (2)缺点: (3)使用场景: (4)注意事项: (5)应用实例: 代码 备忘录模式(memento) 备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对…...

【Agora UID 踩坑记录 Java 数据类型】
目录 负数二进制表示Java中32位无符号数的取法项目踩坑记录Java 0xffffffff隐式类型转换的坑 负数二进制表示 由于计算机中数据都以二进制表示,而负数的二级制是根据正数二进制取补码(补码就是先取反码,然后加1)得到,…...

ESP8285 RTOS SDK OTA
一、官方资源说明 官方指南:空中升级 (OTA) - ESP32 - — ESP-IDF 编程指南 v4.3.6 文档,虽然是正对ESP32的,但是原理是一样的。 官方参考例程:esp-idf\ESP8266_RTOS_SDK\examples\system\ota\,其中包含两个例程&…...

Hadoop3教程(四):HDFS的读写流程及节点距离计算
文章目录 (55)HDFS 写数据流程(56) 节点距离计算(57)机架感知(副本存储节点选择)(58)HDFS 读数据流程参考文献 (55)HDFS 写数据流程 …...

[0xGameCTF 2023] web题解
文章目录 [Week 1]signinbaby_phphello_httprepo_leakping [Week 2]ez_sqli方法一(十六进制绕过)方法二(字符串拼接) ez_upload [Week 1] signin 打开题目,查看下js代码 在main.js里找到flag baby_php <?php /…...

Qt之submodule编译
工作中会遇到这样一种情况:qt应用程序在运行时提示找不到某个qt的动态库。我遇到的是缺少libQt5Websocket.so,因为应用程序是在x86平台银河麒麟v10上开发,能够正常编译运行,然后移植到rk3588(aarch64架构)上…...

Python实现带图形界面的计算器
Python实现带图形界面的计算器 在本文中,我们将使用Python编写一个带有图形用户界面的计算器程序。这个程序将允许用户通过点击按钮或键盘输入数字和操作符,并在显示屏上显示计算结果。 开发环境准备 要运行这个计算器程序,您需要安装Pyth…...

$ vue -Vbash: vue: command not found
$ vue -V bash: vue: command not found报这个错,我们需要找到vue安装路径,添加在环境变量的用户变量中: 1、vue安装路径 2、编辑环境变量 然后重新打开命令框,就可以了...