Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
避免在策略模式中使用服务定位器:基于依赖注入的优雅实现_创想鸟

避免在策略模式中使用服务定位器:基于依赖注入的优雅实现

避免在策略模式中使用服务定位器:基于依赖注入的优雅实现

本文探讨了在策略模式中避免使用服务定位器这一反模式的有效方法。当存在大量策略且每个策略都有复杂依赖时,传统的服务定位器或手动注入会导致代码臃肿和维护困难。教程将详细介绍如何利用依赖注入框架(如Spring)自动收集策略列表,并通过在策略接口中定义判断方法来动态选择合适的策略,从而实现更简洁、可测试且符合DI原则的解决方案。

策略模式与服务定位器的问题

策略模式(strategy pattern)是一种行为设计模式,它允许在运行时选择算法的行为。通常,我们会定义一个策略接口,并由多个具体策略类实现该接口,每个类封装一种特定的算法。一个策略解析器(strategy resolver)负责根据特定条件选择并执行正确的策略。

然而,在实现策略解析器时,一个常见的陷阱是引入服务定位器(Service Locator)模式。服务定位器被认为是一种反模式,因为它隐藏了依赖关系,增加了系统的复杂性和测试难度。考虑以下伪代码示例:

// 策略接口interface StrategyInterface {    void execute();}// 具体策略A, B, C,它们可能有各自的依赖class A implements StrategyInterface {    private Dependency dep;    public A(Dependency dep) {        this.dep = dep;    }    @Override    public void execute() { /* ... */ }}class B implements StrategyInterface {    private AnotherDependency anotherDep;    public B(AnotherDependency anotherDep) {        this.anotherDep = anotherDep;    }    @Override    public void execute() { /* ... */ }}// ... 更多策略// 使用服务定位器的策略解析器class StrategyResolver {    private ServiceLocator locator; // 服务定位器    public StrategyResolver(ServiceLocator locator) {        this.locator = locator;    }    public StrategyInterface resolve(String data) {        if ("conditionX".equals(data)) {            return locator.get(A.class); // 通过服务定位器获取策略实例        } else if ("conditionY".equals(data)) {            return locator.get(B.class);        }        return locator.get(C.class);    }}

上述代码中,StrategyResolver 通过 ServiceLocator 获取具体的策略实例。虽然这解决了策略类 A, B, C 可能具有不同依赖的问题,但 ServiceLocator 的引入使得 StrategyResolver 与容器紧密耦合,并且其依赖不再显式。如果策略数量增加到十个甚至更多,if-else if 链会变得冗长,且 StrategyResolver 的职责变得复杂。

基于依赖注入的策略模式优化

为了避免服务定位器并保持代码的清晰和可测试性,我们可以利用现代依赖注入(DI)框架(如Spring)的特性。核心思想是让DI容器自动收集所有实现了特定策略接口的实例,并将它们注入到策略解析器中。

1. 策略接口与可判断性

首先,我们可以优化策略接口的命名,移除冗余的 “Interface” 后缀,使其更简洁。更重要的是,为策略接口添加一个方法,用于判断当前策略是否适用于给定的上下文数据。

// 策略接口public interface Strategy {    /**     * 判断当前策略是否适用于给定的数据     * @param data 上下文数据     * @return 如果适用则返回 true,否则返回 false     */    boolean appliesTo(String data);    /**     * 执行策略的具体逻辑     */    void execute();}

2. 具体策略实现

每个具体策略类需要实现 Strategy 接口,并提供其 appliesTo 方法的实现,以声明其适用条件。同时,它们可以继续通过构造函数注入自身的依赖。为了让DI容器能够发现这些策略,需要使用相应的注解(如Spring的 @Component 或 @Named)。

import javax.inject.Named; // 或者 org.springframework.stereotype.Component@Named // 或者 @Componentpublic class ConcreteStrategyA implements Strategy {    private SomeDependency dependencyA;    public ConcreteStrategyA(SomeDependency dependencyA) {        this.dependencyA = dependencyA;    }    @Override    public boolean appliesTo(String data) {        // 示例:如果数据是 "typeA",则此策略适用        return "typeA".equals(data);    }    @Override    public void execute() {        System.out.println("Executing ConcreteStrategyA with dependency: " + dependencyA.getName());    }}@Named // 或者 @Componentpublic class ConcreteStrategyB implements Strategy {    private AnotherDependency dependencyB;    public ConcreteStrategyB(AnotherDependency dependencyB) {        this.dependencyB = dependencyB;    }    @Override    public boolean appliesTo(String data) {        // 示例:如果数据是 "typeB",则此策略适用        return "typeB".equals(data);    }    @Override    public void execute() {        System.out.println("Executing ConcreteStrategyB with dependency: " + dependencyB.getDescription());    }}// ... 更多策略

3. 策略解析器的实现

在策略解析器中,我们可以通过构造函数注入一个 List。Spring等DI框架会自动收集所有实现了 Strategy 接口并被容器管理的Bean,并将它们注入到这个列表中。这样,StrategyResolver 的依赖列表就不会随着策略数量的增加而变得过长。

import java.util.List;import java.util.stream.Collectors;import javax.inject.Named; // 或者 org.springframework.stereotype.Component@Named // 或者 @Componentpublic class StrategyResolver {    private final List strategies;    // Spring 会自动注入所有实现了 Strategy 接口的 Bean    public StrategyResolver(List strategies) {        this.strategies = strategies;    }    /**     * 根据输入数据解析并返回适用的策略     * @param data 输入数据     * @return 适用的策略     * @throws IllegalArgumentException 如果没有找到适用的策略     */    public Strategy resolve(String data) {        // 遍历策略列表,找到第一个适用的策略        for (Strategy strategy : strategies) {            if (strategy.appliesTo(data)) {                return strategy;            }        }        throw new IllegalArgumentException("No strategy applies to data: " + data);    }    // 使用 Java 8 Stream API 的更简洁写法    public Strategy resolveWithStream(String data) {        return strategies.stream()                         .filter(strategy -> strategy.appliesTo(data))                         .findFirst() // 或者 findAny(),取决于是否需要特定顺序                         .orElseThrow(() -> new IllegalArgumentException("No strategy applies to data: " + data));    }}

4. 处理无匹配策略和默认策略

在 resolve 方法中,如果没有任何策略适用,我们抛出了 IllegalArgumentException。在某些场景下,我们可能不希望抛出异常,而是提供一个默认行为。这可以通过引入一个“默认策略”来实现:

import java.util.ArrayList;import java.util.List;import javax.inject.Named; // 或者 org.springframework.stereotype.Component@Named // 或者 @Componentpublic class DefaultStrategy implements Strategy {    @Override    public boolean appliesTo(String data) {        return true; // 默认策略总是适用    }    @Override    public void execute() {        System.out.println("Executing DefaultStrategy: No specific strategy found.");    }}@Named // 或者 @Componentpublic class StrategyResolverWithDefault {    private final List strategies;    // 注入所有策略和默认策略    public StrategyResolverWithDefault(List strategies, DefaultStrategy defaultStrategy) {        // 创建一个新的列表,将所有具体策略添加进去        this.strategies = new ArrayList(strategies);        // 将默认策略添加到列表的末尾,确保它在所有其他策略之后被检查        this.strategies.add(defaultStrategy);    }    public Strategy resolve(String data) {        return strategies.stream()                         .filter(strategy -> strategy.appliesTo(data))                         .findFirst()                         .orElseThrow(() -> new IllegalStateException("This should not happen if DefaultStrategy is present."));        // 如果DefaultStrategy被正确添加,这里永远不会抛出异常    }}

通过将 DefaultStrategy 添加到策略列表的末尾,我们可以确保它只有在所有其他具体策略都不适用时才会被选中,从而提供一个优雅的降级方案。

总结

通过上述方法,我们成功地在策略模式中避免了服务定位器这一反模式。这种基于依赖注入的实现方式带来了诸多优势:

解耦性强: StrategyResolver 不再依赖于具体的DI容器实现,而是依赖于 List 接口,提高了模块间的解耦。可测试性高: StrategyResolver 可以轻松地通过模拟(Mock)List 进行单元测试,无需启动完整的DI容器。扩展性好: 增加新的策略时,只需创建新的策略类并实现 Strategy 接口,DI容器会自动发现并将其注入到 StrategyResolver 中,无需修改现有代码(遵循开闭原则)。代码简洁: StrategyResolver 的构造函数和 resolve 方法保持简洁,避免了冗长的条件判断和手动实例化逻辑。

这种模式在处理大量策略且每个策略都有自身复杂依赖的场景下尤其有效,它提供了一种优雅、可维护且符合现代软件设计原则的解决方案。

以上就是避免在策略模式中使用服务定位器:基于依赖注入的优雅实现的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1273797.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
WordPress中setcookie即时读取失效:理解与解决方案
上一篇 2025年12月10日 16:00:27
在 Laravel 辅助函数中获取调用控制器和方法信息
下一篇 2025年12月10日 16:00:41

相关推荐

  • 豆包无需安装秒启动 豆包AI智能助手即时响应

    豆包无需安装秒启动 豆包AI智能助手即时响应豆包无需安装秒启动 豆包AI智能助手即时响应豆包无需安装秒启动 豆包AI智能助手即时响应豆包无需安装秒启动 豆包AI智能助手即时响应

    全民k歌:歌房舞台效果开启指南 腾讯出品的全民K歌,以其智能打分、修音、混音和专业音效等功能,深受K歌爱好者喜爱。本教程将详细指导您如何在全民K歌歌房中开启炫酷的舞台效果。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 步骤: 打开全民K歌…

    2026年9月28日 • 用户投稿
    000
  • firefox浏览器如何关闭自动更新 Firefox浏览器禁用自动更新设置方法

    firefox浏览器如何关闭自动更新 Firefox浏览器禁用自动更新设置方法firefox浏览器如何关闭自动更新 Firefox浏览器禁用自动更新设置方法firefox浏览器如何关闭自动更新 Firefox浏览器禁用自动更新设置方法firefox浏览器如何关闭自动更新 Firefox浏览器禁用自动更新设置方法

    如果您发现Firefox浏览器在后台自动更新,影响了您的使用习惯或系统稳定性,可以通过修改设置来阻止其自动更新。以下是几种可行的关闭方法。 本文运行环境:Dell XPS 13,Windows 11 一、通过Firefox内置设置禁用自动更新 Firefox提供了直接在选项中关闭自动更新的功能,适合…

    2026年9月28日 • 用户投稿
    000
  • 滴答清单怎么共享清单给好友协作_滴答清单清单共享与多人协作设置教程

    滴答清单怎么共享清单给好友协作_滴答清单清单共享与多人协作设置教程滴答清单怎么共享清单给好友协作_滴答清单清单共享与多人协作设置教程滴答清单怎么共享清单给好友协作_滴答清单清单共享与多人协作设置教程滴答清单怎么共享清单给好友协作_滴答清单清单共享与多人协作设置教程

    可通过链接、联系人或邮箱三种方式共享滴答清单任务列表。首先打开目标清单,点击右上角“共享”按钮,选择“创建共享链接”并发送链接给好友,对方点击即可加入协作;或选择“添加成员”,从通讯录中选取联系人并设置查看、编辑或管理权限;若合作者不在通讯录,可使用“通过邮箱邀请”功能输入邮箱地址发送邀请,对方登录…

    2026年9月28日 • 用户投稿
    000
  • Safari浏览器iCloud标签页不显示怎么办_Safari浏览器iCloud标签页同步问题解决方案

    Safari浏览器iCloud标签页不显示怎么办_Safari浏览器iCloud标签页同步问题解决方案Safari浏览器iCloud标签页不显示怎么办_Safari浏览器iCloud标签页同步问题解决方案Safari浏览器iCloud标签页不显示怎么办_Safari浏览器iCloud标签页同步问题解决方案Safari浏览器iCloud标签页不显示怎么办_Safari浏览器iCloud标签页同步问题解决方案

    首先确认Apple ID登录一致,检查iCloud标签页同步开关是否开启,重启同步服务并验证系统时间与网络连接,尝试重启设备或重新登录Apple ID以解决iCloud标签页不同步问题。 如果您在使用Safari浏览器时发现iCloud标签页未能正确显示或同步,可能是由于账户设置、网络连接或系统配置…

    2026年9月28日 • 用户投稿
    200
  • TikTok私信显示异常怎么办

    TikTok私信显示异常怎么办TikTok私信显示异常怎么办TikTok私信显示异常怎么办TikTok私信显示异常怎么办

    私信异常多因设置、规则或技术问题,需检查互关状态、隐私权限、年龄限制及网络状况,排除违规行为并更新应用,必要时联系官方客服处理。 当TikTok私信显示异常时,可能是由多种原因导致的,包括账号设置、平台规则限制或技术问题。要解决这个问题,需要从多个方面逐一排查和处理。 检查账号设置与互动条件 私信功…

    2026年9月28日 • 用户投稿
    100
  • 抖音的私信关了怎么开启?私信关了对方发信息显示什么?

    抖音的私信关了怎么开启?私信关了对方发信息显示什么?抖音的私信关了怎么开启?私信关了对方发信息显示什么?抖音的私信关了怎么开启?私信关了对方发信息显示什么?抖音的私信关了怎么开启?私信关了对方发信息显示什么?

    抖音的私信功能是用户之间交流的重要工具,但有时可能因设置调整而被关闭。本文将为您详细说明如何重新打开私信权限,并介绍关闭后他人发送消息时会看到哪些提示,助您更好地掌控社交互动与隐私安全。 一、抖音私信关闭了如何重新开启? 若您发现无法收到或发送私信,很可能是私信接收权限被关闭。只需几个简单步骤即可恢…

    2026年9月28日 • 用户投稿
    100
  • Linux ulimit命令详解与使用方法

    ulimit用于限制进程资源,如文件大小、进程数和内存;默认显示文件大小软限制,常用选项包括-f、-n、-u等,软限制可由用户调整,硬限制需root修改;通过ulimit -a查看所有限制,设置如ulimit -n 1024可限制打开文件数;永久配置需编辑/etc/security/limits.c…

    2026年9月28日
    100
  • 在线小说阅读平台排名2025-完结小说免费观看网站推荐

    在线小说阅读平台排名2025-完结小说免费观看网站推荐在线小说阅读平台排名2025-完结小说免费观看网站推荐在线小说阅读平台排名2025-完结小说免费观看网站推荐在线小说阅读平台排名2025-完结小说免费观看网站推荐

    起点、番茄、七猫是2025年看完结小说的主流平台,起点书库经典多,番茄免费资源丰富且分类清晰,七猫女频完结作品全,三者均支持免费阅读,适合不同偏好的读者。 想找2025年靠谱的在线小说平台看完结书?免费资源多、体验好的平台其实集中在几家大厂旗下。下面这几个,不仅书库全,完结作品丰富,而且支持直接阅读…

    2026年9月28日 • 用户投稿
    200
  • sublime怎么配置python的虚拟环境_Python虚拟环境集成指南

    sublime怎么配置python的虚拟环境_Python虚拟环境集成指南sublime怎么配置python的虚拟环境_Python虚拟环境集成指南sublime怎么配置python的虚拟环境_Python虚拟环境集成指南sublime怎么配置python的虚拟环境_Python虚拟环境集成指南

    答案是通过创建自定义构建系统和配置项目文件确保Sublime Text使用指定虚拟环境。具体做法包括:在.sublime-build文件中指定虚拟环境Python解释器路径,结合.cmd字段设置无缓冲运行参数-u,并在.sublime-project文件中为项目定义独立的build_systems与…

    2026年9月28日 • 用户投稿
    100
  • 夸克怎么彻底卸载干净_夸克APP及相关数据完全清除教程

    夸克怎么彻底卸载干净_夸克APP及相关数据完全清除教程夸克怎么彻底卸载干净_夸克APP及相关数据完全清除教程夸克怎么彻底卸载干净_夸克APP及相关数据完全清除教程夸克怎么彻底卸载干净_夸克APP及相关数据完全清除教程

    彻底卸载夸克APP需先通过系统设置卸载主程序,再手动删除残留文件夹如/Android/data/com.quark.browser,清除账户同步数据,并使用清理工具深度扫描残留项。 如果您尝试从设备中移除夸克应用,但发现残留数据或配置文件仍然存在,则可能是由于卸载过程中未清除用户数据与缓存信息。以下…

    2026年9月28日 • 用户投稿
    100
  • Linux学习笔记(二)系统基础操作

    Linux学习笔记(二)系统基础操作Linux学习笔记(二)系统基础操作Linux学习笔记(二)系统基础操作Linux学习笔记(二)系统基础操作

    Linux基础学习笔记精选专栏 本专栏由小雨ttt创建,致力于分享学习linux基础知识的过程。本专栏不是机械地介绍linux指令集,而是包含了作者亲自实践的操作过程,站在一个初学者的角度理解linux基础知识。 目前本专栏包含的内容有: Linux学习笔记(一)使用文本编辑器VimLinux学习笔…

    2026年9月28日 • 用户投稿
    100
  • sublime怎么保存时自动格式化代码_Sublime配置保存时自动格式化代码方法

    sublime怎么保存时自动格式化代码_Sublime配置保存时自动格式化代码方法sublime怎么保存时自动格式化代码_Sublime配置保存时自动格式化代码方法sublime怎么保存时自动格式化代码_Sublime配置保存时自动格式化代码方法sublime怎么保存时自动格式化代码_Sublime配置保存时自动格式化代码方法

    安装插件并配置可实现Sublime Text保存时自动格式化代码,提升代码可读性与一致性。首先安装Package Control包管理器,通过控制台执行指定代码完成安装;重启后使用命令面板(Ctrl+Shift+P)调出Package Control: Install Package,搜索并安装所需…

    2026年9月28日 • 用户投稿
    900
  • 百度搜索app如何快速切换账号_百度搜索app多账号管理的操作方法

    百度搜索app如何快速切换账号_百度搜索app多账号管理的操作方法百度搜索app如何快速切换账号_百度搜索app多账号管理的操作方法百度搜索app如何快速切换账号_百度搜索app多账号管理的操作方法百度搜索app如何快速切换账号_百度搜索app多账号管理的操作方法

    1、可通过设置菜单退出当前账号后登录新账号实现切换;2、安卓用户可使用应用分身功能创建百度App双开实例,分别登录不同账号;3、符合条件的iOS设备可利用巨魔商店安装修改版百度App实现多开,从而同时登录多个账号。 如果您需要在百度搜索App中频繁使用不同的账号进行登录,但每次都需要退出再重新登录,…

    2026年9月28日 • 用户投稿
    1100
  • Kook电脑版官方入口 _ KOOK网页版在线登录平台

    Kook电脑版官方入口 _ KOOK网页版在线登录平台Kook电脑版官方入口 _ KOOK网页版在线登录平台Kook电脑版官方入口 _ KOOK网页版在线登录平台Kook电脑版官方入口 _ KOOK网页版在线登录平台

    KOOK电脑版官方入口是https://www.kookapp.cn/,提供稳定语音通话、文字聊天、文件传输等功能,支持跨设备同步与社区互动。 KOOK电脑版官方入口在哪里?这是许多用户都在寻找的信息,接下来由PHP小编为大家带来KOOK电脑版及网页版的在线登录平台地址,想了解这个平台特点的朋友,一…

    2026年9月28日 • 用户投稿
    200
  • KOOK官方下载中心 _ Kook语音网页版账号登录

    KOOK官方下载中心 _ Kook语音网页版账号登录KOOK官方下载中心 _ Kook语音网页版账号登录KOOK官方下载中心 _ Kook语音网页版账号登录KOOK官方下载中心 _ Kook语音网页版账号登录

    KOOK官方下载中心位于其官网https://www.kookapp.cn/,提供桌面端、移动端及网页版登录方式;平台支持多模式语音频道、文字互动、机器人接入及屏幕共享功能;客户端覆盖Windows、macOS与主流手机系统,具备低延迟、低资源占用与多端消息同步优势;网页版无需下载,兼容主流浏览器,…

    2026年9月28日 • 用户投稿
    100
  • mac怎么安装win10双系统_mac安装Win10双系统方法

    答案:Intel芯片Mac可使用启动转换助理安装Windows 10双系统,M系列芯片则需通过虚拟机实现。具体包括下载ISO镜像、创建分区或U盘启动盘、安装系统及驱动等步骤,确保硬件兼容与数据安全。 如果您希望在Mac电脑上运行Windows 10应用程序或游戏,可能需要通过双系统方式安装Windo…

    2026年9月28日
    200
  • 使用云 Firestore 在服务器端处理数据以优化 Android 应用性能

    正如前文摘要所述,本文将介绍如何将 Android 应用中 Cloud Firestore 的数据处理逻辑迁移至服务器端,从而提高应用的性能和可维护性。 在 Android 应用开发中,直接在客户端执行大量的 Firestore CRUD(创建、读取、更新、删除)操作可能会导致应用运行缓慢,并且代码…

    2026年9月28日
    500
  • 宜鼎携全栈创新成果PTEXPO 2025亮相智构AI存储新生态

    宜鼎携全栈创新成果PTEXPO 2025亮相智构AI存储新生态宜鼎携全栈创新成果PTEXPO 2025亮相智构AI存储新生态宜鼎携全栈创新成果PTEXPO 2025亮相智构AI存储新生态宜鼎携全栈创新成果PTEXPO 2025亮相智构AI存储新生态

    9月24日,素有“ict行业风向标”之称的中国国际信息通信展览会(pt expo 2025)在北京国家会展中心盛大启幕。全球领先的ai解决方案与工业级存储品牌宜鼎国际(innodisk)重磅亮相,以“智构未来|architect intelligence”为主题,全面展示其在工业存储、边缘ai及5g…

    2026年9月28日 • 用户投稿
    100
  • 淘宝购物车商品消失如何处理

    淘宝购物车商品消失如何处理淘宝购物车商品消失如何处理淘宝购物车商品消失如何处理淘宝购物车商品消失如何处理

    购物车商品消失主因是系统自动清理或商品下架;2. 可通过足迹找回、联系客服或重新登录解决;3. 定期互动和收藏可预防丢失。 淘宝购物车里的商品突然不见了,先别急,这通常有几种原因和对应的解决办法。 检查是否被系统自动清理 淘宝会对长时间未操作的购物车商品进行清理,尤其是临近60天未登录或未互动的商品…

    2026年9月28日 • 用户投稿
    100
  • 12306手机App如何为他人代买车票 12306手机App家庭购票的便捷操作

    12306手机App如何为他人代买车票 12306手机App家庭购票的便捷操作12306手机App如何为他人代买车票 12306手机App家庭购票的便捷操作12306手机App如何为他人代买车票 12306手机App家庭购票的便捷操作12306手机App如何为他人代买车票 12306手机App家庭购票的便捷操作

    首先添加乘车人信息至12306账户,完成实名核验;2. 查询并选择合适的车次;3. 提交订单时选择已添加的乘车人;4. 支付成功后系统自动推送购票信息,完成代购。 如果您想为家人或朋友购买火车票,但又不想让他们亲自操作或排队购票,可以通过铁路12306官方App轻松实现代购。以下是详细的代购票操作方…

    2026年9月28日 • 用户投稿
    100

发表回复

登录后才能评论
关注微信