Spring framework Day11:策略模式中注入所有实现类

前言

什么是策略模式?

策略模式(Strategy Pattern)是一种面向对象设计模式,它定义了算法族(一组相似的算法),并且将每个算法都封装起来,使得它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。

在策略模式中,定义一个抽象的策略接口或者抽象类来封装不同的具体算法实现,并由客户端根据需要动态选择使用哪种算法。这种方式支持应用程序灵活地更换算法和扩展算法,而无需修改已有代码。此外,策略模式可以减少大量的 if-else 语句,提高代码的可读性和可维护性。

策略模式通常包含三个角色:

  1. 环境(Context)角色:通过一个持有某个策略实例的变量来调用具体的策略算法。

  2. 抽象策略(Strategy)角色:定义了一个公共的接口或抽象类,规定了所有具体策略角色必须实现的方法。

  3. 具体策略(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 注解的字段的构造函数。

控制器类中声明了一个名为 contextPaymentContext 类型的成员变量,用于存储策略上下文对象。

pay 方法中,根据传入的 typemoney 参数,调用 contextpay 方法来执行具体的支付逻辑。这里的 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 容器的支持,我们可以方便地管理和维护各个支付类型的具体支付策略,同时也能够方便地进行扩展和配置。

 

二、使用策略模式注入所有实现类的好处 

使用策略模式注入所有实现类的好处主要有以下几个方面:

  1. 解耦性:通过策略模式,将具体的实现类与调用它们的类解耦。调用方只需要依赖于抽象的策略接口或基类,而不需要关心具体的实现类。这样可以降低类之间的耦合度,并且使得系统更加灵活和可维护。

  2. 可扩展性:当新增一种支付类型时,只需实现相应的支付策略,并注册到容器中即可,无需修改调用方的代码。通过容器自动注入所有实现类,实现类的新增和移除变得方便快捷,可以根据业务需求随时扩展支付策略。

  3. 可配置性:通过注入所有实现类,可以将不同的实现类配置到容器的配置文件中,而不需要修改源代码。这样在不同的环境中,可以通过简单的配置文件修改支付策略的选择,而无需重新编译和部署代码。

  4. 单一职责原则:通过策略模式,每个具体的支付策略类只需要关注自身特定的支付逻辑,符合单一职责原则。这样可以提高代码的可读性、可维护性和可测试性。

总之,使用策略模式注入所有实现类具有解耦性、可扩展性、可配置性和单一职责原则等优点,使得系统更加灵活、可维护和可测试。

三、gitee 案例

案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vmware Linux虚拟机安装教程(Centos版)

文章目录 1.Vmware-workstation安装软件2.双击下载的安装包开始安装3.打开VMware-workstation&#xff0c;输入密钥4.Centos7.6安装软件5.新建虚拟机6.为虚拟机配置映像文件7.开启虚拟机&#xff0c;配置环境7.1 Install Centos 77.2 选择简体中文字体7.3 软件选择7.4 安装位置…

网络基础(2)

UDP 1.传输层2.再谈端口号3.端口号范围划分4.认识知名端口号(Well-Know Port Number)5.netstat6.pidof7.UDP协议端格式8.UDP的特点9.面向数据报10.UDP的缓冲区11.UDP使用注意事项12.基于UDP的应用层协议 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&am…

动态内存管理+柔性数组+经典笔试题

&#x1f493;博客主页&#xff1a;江池俊的博客⏩收录专栏&#xff1a;C语言进阶之路&#x1f449;专栏推荐&#xff1a;✅C语言初阶之路 ✅数据结构探索&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐ 文…

分布式文件服务器——Windows环境MinIO的三种部署模式

上节简单聊到MinIO&#xff1a;分布式文件存储服务——初识MinIO-CSDN博客&#xff0c;但没具化&#xff0c;本节开始展开在Windows环境下 MinIO的三种部署模式&#xff1a;单机单节点、单机纠删码、集群模式。 部署的几种模式简要概括 所谓单机单节点模式&#xff1a;即MinI…

AI :微软推出 AutoGen 框架,帮开发者创建基于大语言模型的复杂应用

本心、输入输出、结果 文章目录 AI :微软推出 AutoGen 框架,帮开发者创建基于大语言模型的复杂应用前言AutoGen 简介快速入门AutoGen 安装相关支持相关代码相关架构图弘扬爱国精神AI :微软推出 AutoGen 框架,帮开发者创建基于大语言模型的复杂应用 编辑:简简单单 Online z…

B树、B+树详解

B树 前言   首先&#xff0c;为什么要总结B树、B树的知识呢&#xff1f;最近在学习数据库索引调优相关知识&#xff0c;数据库系统普遍采用B-/Tree作为索引结构&#xff08;例如mysql的InnoDB引擎使用的B树&#xff09;&#xff0c;理解不透彻B树&#xff0c;则无法理解数据…

关于TCP协议面试中常见的一千个问题

TCP传输层控制协议 TCP是面向连接的、可靠的、基于字节流的传输层通信协议。 TCP 头部格式 1、 源端口和目的端口字段——各占 2 字节。端口是运输层与应用层的服务接口。运输层的复用和分用功能都要通过端口才能实现。 2、 序号字段——占 4 字节。TCP 连接中传送的数据流中…

1、验证1101序列(Moore)

题目要求&#xff1a; 用Moore型状态机验证1101序列。 题目描述&#xff1a; 用使用状态机验证1101序列&#xff0c;注意&#xff1a;允许重复子序列。如图 端口描述&#xff1a; module moore_1101(input clk,//时钟信号input clr,//reset复位信号&#xff0c;高电平有效in…

MATLAB——BP神经网络信号拟合程序

欢迎关注公众号“电击小子程高兴的MATLAB小屋” %% 学习目标&#xff1a;BP神经网络 %% 函数逼近 数据压缩 模式识别 %% 考虑要素&#xff1a;网络层数 输入层的节点数 输出层的节点数 隐含层的节点数 %% 传输函数 训练方法 %% 对信号曲线进行拟合 clear all; cle…

Vue鼠标右键画矩形和Ctrl按键多选组件

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

记一次使用vue-markdown在vue中解析markdown格式文件,并自动生成目录大纲

先上效果图 如图所示&#xff0c;在网页中&#xff0c;能直接解析markdown文档&#xff0c;并且生成目录大纲&#xff0c;也支持点击目录标题跳转到对应栏目中&#xff0c;下面就来讲讲是如何实现此功能的。 1、下载vue-markdown yarn add vue-markdown 2、在页面中渲染markdo…

Jenkins+Gitlab+Docker(Dockerfile)部署

Docker部署运行 ​ 上一篇内容中使用Jenkins(运行服务器)Gitlab(代码存储库)Webhook(网络钩子)的方式部署运行我们的项目。需要我们在服务器上做好很多相关的环境配置及依赖。 ​ 那么假如有这样一个场景&#xff1a;需要把不同技术栈的项目部署到同一台服务器上运行。比如PH…