阿里巴巴网站建设的不足之处,网站建设标书模板,济南百度提升优化,wordpress企业建站教程Spring中实现策略模式示例
在本教程中#xff0c;将探索 Spring 框架中的各种策略模式实现#xff0c;例如列表注入、映射注入和方法注入。
什么是策略模式#xff1f; 策略模式是一种设计原则#xff0c;允许您在运行时切换不同的算法或行为。它允许您在不改变应用程序核…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 MapString, CurseStrategy curses; public DarkArtsMapWizard(MapString, 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 MapString, 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 MapString, 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 功能的优化解决方案。
原文