Spring中实现策略模式示例

Spring中实现策略模式示例

在本教程中,将探索 Spring 框架中的各种策略模式实现,例如列表注入、映射注入和方法注入。

什么是策略模式?
策略模式是一种设计原则,允许您在运行时切换不同的算法或行为。它允许您在不改变应用程序核心逻辑的情况下插入不同的策略,从而使您的代码具有灵活性和适应性。

这种方法适用于为特定功能任务提供不同实现方式,并使系统更能适应变化的情况。它通过将算法细节与应用程序的主要逻辑分离,促进了更模块化的代码结构。

步骤 1:实施策略
把自己想象成一个黑暗巫师,努力与春天一起掌握不可饶恕诅咒的力量。我们的任务是实现所有三种诅咒--Avada Kedavra、Crucio 和 Imperio。之后,我们将在运行时切换不同的诅咒(策略)。

让我们从策略接口开始:

public interface CurseStrategy {  

    String useCurse();

    String curseName();
}

下一步,我们需要执行所有 "不可饶恕的诅咒":

@Component  
public class CruciatusCurseStrategy implements CurseStrategy {  

@Override  
public String useCurse() {  
return "Attack with Crucio!";  
}  

@Override  
public String curseName() {  
return "Crucio";  
}  
}

@Component  
public class ImperiusCurseStrategy implements CurseStrategy {  

@Override  
public String useCurse() {  
return "Attack with Imperio!";  
}  

@Override  
public String curseName() {  
return "Imperio";  
}  
}

@Component  
public class KillingCurseStrategy implements CurseStrategy {  

@Override  
public String useCurse() {  
return "Attack with Avada Kedavra!";  
}  

@Override  
public String curseName() {  
return "Avada Kedavra";  
}  
}

第 2 步:将诅咒注入 List
Spring 提供了一个神奇的功能,允许我们以 List 的形式注入一个接口的多个实现,这样我们就可以用它来注入策略并在它们之间切换。

但让我们先创建基础:Wizard接口。

public interface Wizard {  
String castCurse(String name); 
}

我们可以在向导中注入我们的诅咒(策略),并筛选出所需的诅咒。

@Service  
public class DarkArtsWizard implements Wizard {  

private final List curses;  

public DarkArtsListWizard(List curses) {  
this.curses = curses;  
}  

@Override  
public String castCurse(String name) {  
return curses.stream()  
.filter(s -> name.equals(s.curseName()))  
.findFirst()  
.orElseThrow(UnsupportedCurseException:: new)  
.useCurse();  
}  
}

如果请求的诅咒不存在,也会产生 UnsupportedCurseException。

public class UnsupportedCurseException extends RuntimeException {  
}

测试
我们可以验证诅咒施放是否有效:

@SpringBootTest  
class DarkArtsWizardTest {  

@Autowired  
private DarkArtsWizard wizard;  

@Test  
public void castCurseCrucio() {  
assertEquals("Attack with Crucio!", wizard.castCurse("Crucio"));  
}  

@Test  
public void castCurseImperio() {  
assertEquals("Attack with Imperio!", wizard.castCurse("Imperio"));  
}  

@Test  
public void castCurseAvadaKedavra() {  
assertEquals("Attack with Avada Kedavra!", wizard.castCurse("Avada Kedavra"));  
}  

@Test  
public void castCurseExpelliarmus() {  
assertThrows(UnsupportedCurseException.class, () -> wizard.castCurse("Abrakadabra"));  
}  
}

另一种流行的方法是定义 canUse 方法,而不是 curseName。这将返回布尔值,并允许我们使用更复杂的过滤功能,例如

public interface CurseStrategy {  

    String useCurse();

    boolean canUse(String name, String wizardType);
}

@Component  
public class CruciatusCurseStrategy implements CurseStrategy {  

@Override  
public String useCurse() {  
return "Attack with Crucio!";  
}  

@Override  
public boolean canUse(String name, String wizardType) {  
return "Crucio".equals(name) && "Dark".equals(wizardType);  
}  
}

@Service  
public class DarkArtstWizard implements Wizard {  

private final List curses;  

public DarkArtsListWizard(List curses) {  
this.curses = curses;  
}  

@Override  
public String castCurse(String name) {  
return curses.stream()  
.filter(s -> s.canUse(name, "Dark")))  
.findFirst()  
.orElseThrow(UnsupportedCurseException:: new)  
.useCurse();  
}  
}

步骤 3:将策略注入Map
我们可以轻松解决上一节中的弊端。Spring 允许我们将 Bean 名称和实例注入 Map。它简化了代码并提高了效率。

@Service  
public class DarkArtsWizard implements Wizard {  

private final Map<String, CurseStrategy> curses;  

public DarkArtsMapWizard(Map<String, CurseStrategy> curses) {  
this.curses = curses;  
}  

@Override  
public String castCurse(String name) {  
CurseStrategy curse = curses.get(name);  
if (curse == null) {  
throw new UnsupportedCurseException();  
}  
return curse.useCurse();  
}  
}

这种方法有一个缺点:Spring 会注入 Bean 名称作为 Map 的键,因此策略名称与 Bean 名称相同,如 cruciatusCurseStrategy。如果 Spring 的代码或我们的类名在未通知的情况下发生变化,这种对 Spring 内部 Bean 名称的依赖可能会导致问题。

让我们检查一下,我们是否仍能施放这些诅咒:

@SpringBootTest  
class DarkArtsWizardTest {  

@Autowired  
private DarkArtsWizard wizard;  

@Test  
public void castCurseCrucio() {  
assertEquals("Attack with Crucio!", wizard.castCurse("cruciatusCurseStrategy"));  
}  

@Test  
public void castCurseImperio() {  
assertEquals("Attack with Imperio!", wizard.castCurse("imperiusCurseStrategy"));  
}  

@Test  
public void castCurseAvadaKedavra() {  
assertEquals("Attack with Avada Kedavra!", wizard.castCurse("killingCurseStrategy"));  
}  

@Test  
public void castCurseExpelliarmus() {  
assertThrows(UnsupportedCurseException.class, () -> wizard.castCurse("Crucio"));  
}  
}

  • 优点:无循环。
  • 缺点:依赖于 Bean 名称,这使得代码的可维护性较差,并且在名称更改或重构时更容易出错。

步骤 4:注入 List 并将其转换为 Map
如果我们注入 List 并将其转换为 Map,就可以轻松消除 Map 注入的弊端:

@Service  
public class DarkArtsWizard implements Wizard {  

private final Map<String, CurseStrategy> curses;  

public DarkArtsMapWizard(List curses) {  
this.curses = curses.stream()  
.collect(Collectors.toMap(CurseStrategy::curseName, Function.identity()));
}  

@Override  
public String castCurse(String name) {  
CurseStrategy curse = curses.get(name);  
if (curse == null) {  
throw new UnsupportedCurseException();  
}  
return curse.useCurse();  
}  
}

有了这种方法,我们就可以使用 curseName 代替 Spring 的 Bean 名称作为 Map 键(策略名称)。

步骤 5:接口中的 @Autowire
Spring 支持在方法中自动布线。自动连接到方法的简单示例是通过设置器注入。此功能允许我们在接口的默认方法中使用 @Autowired,这样我们就可以在向导接口中注册每个 CurseStrategy,而无需在每个策略实现中实现注册方法。

让我们通过添加 registerCurse 方法来更新Wizard接口:

public interface Wizard {  

String castCurse(String name);  

void registerCurse(String curseName, CurseStrategy curse)
}
@Service  
public class DarkArtsWizard implements Wizard {  

private final Map<String, CurseStrategy> curses = new HashMap<>();  

@Override  
public String castCurse(String name) {  
CurseStrategy curse = curses.get(name);  
if (curse == null) {  
throw new UnsupportedCurseException();  
}  
return curse.useCurse();  
}  

@Override  
public void registerCurse(String curseName, CurseStrategy curse) {  
curses.put(curseName, curse);  
}  
}

现在,让我们通过添加带有 @Autowired 注解的方法来更新 CurseStrategy 接口:

public interface CurseStrategy {  

String useCurse();  

String curseName();  

@Autowired  
default void registerMe(Wizard wizard) {  
wizard.registerCurse(curseName(), this);  
}  
}

在注入依赖项的同时,我们将诅咒注册到向导中。

  • 优点:没有循环,也不依赖内部 Spring Bean 名称。
  • 缺点:没有缺点,纯粹的黑魔法。

结论
在本文中,我们探讨了 Spring 环境中的策略模式。我们评估了不同的策略注入方法,并演示了使用 Spring 功能的优化解决方案。

原文

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

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

相关文章

Spring及工厂模式概述

文章目录 Spring 身世什么是 Spring什么是设计模式工厂设计模式什么是工厂设计模式简单的工厂设计模式通用的工厂设计 总结 在 Spring 框架出现之前&#xff0c;Java 开发者使用的主要是传统的 Java EE&#xff08;Java Enterprise Edition&#xff09;平台。Java EE 是一套用于…

《Docker 简易速速上手小册》第3章 Dockerfile 与镜像构建(2024 最新版)

文章目录 3.1 编写 Dockerfile3.1.1 重点基础知识3.1.2 重点案例&#xff1a;创建简单 Python 应用的 Docker 镜像3.1.3 拓展案例 1&#xff1a;Dockerfile 优化3.1.4 拓展案例 2&#xff1a;多阶段构建 3.2 构建流程深入解析3.2.1 重点基础知识3.2.2 重点案例&#xff1a;构建…

港科夜闻|香港科大计划建立北部都会区卫星校园完善科大创新带,发展未来创新科技 未来医药发展及跨学科教育...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大计划建立北部都会区卫星校园完善“科大创新带”&#xff0c;发展未来创新科技、未来医药发展及跨学科教育。香港科大校长叶玉如教授在2月22日的媒体会议上表示&#xff0c;香港科大将在北部都会区建立卫星校园&a…

open3d KD-Tree K近邻点搜索

open3d KD-Tree K近邻点搜索 一、算法原理1.KD-Tree 介绍2.原理 二、代码三、结果1.原点云2.k近邻点搜索后的点云 四、相关数据 一、算法原理 1.KD-Tree 介绍 kd 树或 k 维树是计算机科学中使用的一种数据结构&#xff0c;用于在具有 k 维的空间中组织一定数量的点。它是一个…

【Spring MVC】处理器映射器:AbstractHandlerMethodMapping源码分析

目录 一、继承体系 二、HandlerMapping 三、AbstractHandlerMapping 四、AbstractHandlerMethodMapping 4.1 成员属性 4.1.1 MappingRegistry内部类 4.2 AbstractHandlerMethodMapping的初始化 4.3 getHandlerInternal()方法&#xff1a;根据当前的请求url&#xff0c;…

从git上clone项目到本地后启动时的一种报错

当我们从git上拉项目到本地之后&#xff0c;先install,但启动时可能会出现报错&#xff0c;例如上面这种报错&#xff0c;这时候我们需要把package.json里的vite改一下&#xff0c;例如改成2.6.13&#xff0c;之后删掉node_modules,重新install,再启动一下&#xff0c;就好了。…

OT 安全解决方案:探索技术

IT 和 OT 安全的融合&#xff1a;更好的防御方法 OT 安全解决方案下一个时代&#xff1a; 为了应对不断升级的威胁形势&#xff0c;组织认识到迫切需要采用统一的信息技术 (IT) 和运营技术 (OT) 安全方法。IT 和 OT 安全的融合代表了一种范式转变&#xff0c;承认这些传统孤立领…

音频smmu问题之smmu学习

一、音频smmu 内存访问问题 在工作中&#xff0c;遇到一个smmu问题&#xff0c;主要log信息如下&#xff1a; arm-smmu 15000000.apps-smmu: Unhandled arm-smmu context fault from soc:spf_core_platform:qcom,msm-audio-ion! arm-smmu 15000000.apps-smmu: FAR 0x0000000…

什么是负载均衡集群?

目录 1、集群是什么&#xff1f; 2、负载均衡集群技术 3、负载均衡集群技术的实现 4、实现效果如图 5、负载均衡分类 6、四层负载均衡&#xff08;基于IP端口的负载均衡&#xff09; 7、七层的负载均衡&#xff08;基于虚拟的URL或主机IP的负载均衡) 8、四层负载与七层…

数据库-MySQL

建立索引 mysql 添加索引的三种方法 - krt-wanyi - 博客园 (cnblogs.com) 跨库联表查询 MySQL不同数据库不同表连表查询&#xff08;跨库连表查询&#xff09;-CSDN博客 关于微服务跨数据库联合查询的一些解决思路_微服务跨库联表查询-CSDN博客 同一个连接不同数据库前缀 …

(3)(3.6) 用于OpenTX的Yaapu遥测脚本

文章目录 前言 1 安装和操作 2 参数说明 前言 这是一个开源 LUA 脚本&#xff0c;用于在使用 OpenTX 2.2.3 的 Horus X10、X12、Jumper T16、T18、Radiomaster TX16S、Taranis X9D、X9E、QX7 和 Jumper T12 无线电设备上显示 FrSky 的直通遥测数据(FrSky passthrough telem…

Linux配置jdk、tomcat、mysql离线安装与启动

目录 1.jdk安装 2.tomcat的安装&#xff08;开机自启动&#xff09; 3.MySQL的安装 4.连接项目 1.jdk安装 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 解压安装包 这里需要解压到usr/local目录下&#xff0c;在这里我新建一个文件夹…

Java实战:Profiles环境切换与多环境配置

本文将详细介绍如何在Spring Boot应用程序中使用Profiles进行环境切换和配置多环境。我们将探讨Profiles的基本概念&#xff0c;以及如何使用Spring Boot的Profiles来实现不同环境的配置和管理。此外&#xff0c;我们将通过具体的示例来展示如何在Spring Boot应用程序中配置和使…

【Vue3】学习computed计算属性

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

NXP实战笔记(十):S32K3xx基于RTD-SDK在S32DS上配置CAN通信

目录 1、概述 2、SDK配置 2.1、配置目标 2.2、CAN配置 3、代码实现 4、测试结果 1、概述 S32K3xx的FlexCan与之前的S32K1xx很相似,Can的中断掩码寄存器(IMASK3)与中断标志位寄存器(IFLAG3)依赖于邮箱数。 FlexCan配置实例如下 FlexCan的整体图示如下 Protocol Engine…

PyTorch概述(六)---View

Tensor.view(*shape)-->Tensor 返回一个新的张量同之前的张量具有相同的数据&#xff0c;但是具有不同的形状&#xff1b;返回的张量同之前的张量共享相同的数据&#xff0c;必须具有相同数目的元素&#xff0c;可能具有不同的形状&#xff1b;对于经过view操作的张量&…

Python中操作MySQL和SQL Server数据库的基础与实战【第97篇—MySQL数据库】

Python中操作MySQL和SQL Server数据库的基础与实战 在Python中&#xff0c;我们经常需要与各种数据库进行交互&#xff0c;其中MySQL和SQL Server是两个常见的选择。本文将介绍如何使用pymysql和pymssql库进行基本的数据库操作&#xff0c;并通过实际代码示例来展示这些操作。…

MQTT介绍

基本概念 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;由 Andy Stanford-Clark&#xff08;IBM&#xff09; 和 Arlen Nipper&#xff08;Arcom&#xff0c; 现为 Cirrus Link&#xff09; 于 1999 年发布&#xff0c;是…

Visual Studio:Entity设置表之间的关联关系

1、选择表并右键-》新增-》关联 2、设置关联的表及关联关系并“确定”即可

真的是性能优化(压测)-纯思想

文章目录 概要优化指标-MD都是文字看看就行性能优化操作1、代码优化&#xff1a;2、系统配置与环境优化&#xff1a;3、架构与设计&#xff1a;4、~~实施与监控&#xff1a;~~5、~~开发流程和环境管理&#xff1a;~~ 总结 概要 性能优化是一个持续的过程&#xff0c;需要监控、…