Spring 策略模式实现

Spring 策略模式实现:工厂方法与自动注入详解

1. 背景介绍

在复杂的业务系统中,我们常常需要根据不同的场景选择不同的处理策略。本文将详细介绍在 Spring 框架中实现策略模式的两种主要方法。

2. 方案一: 手动注册工厂模式

2.1 定义工厂类

java 复制代码
@Component
public class CalculateHandlerFactory implements InitializingBean, ApplicationContextAware {
    private ApplicationContext applicationContext;

    // 存储不同策略的映射
    private static final Map<String, CalculateHandler> HANDLER_MAP = new HashMap<>();

    // 初始化方法,自动注册所有处理器
    @Override
    public void afterPropertiesSet() throws Exception {
        applicationContext.getBeansOfType(CalculateHandler.class)
                .values()
                .forEach(v -> HANDLER_MAP.putIfAbsent(v.getType(), v));
    }

    // 设置 ApplicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    // 根据类型获取对应的处理器
    public CalculateHandler getCalculateHandler(String calculateType) {
        return HANDLER_MAP.getOrDefault(calculateType, null);
    }
}

2.2 实现步骤

  1. 实现 InitializingBean 接口,在 Bean 初始化时自动注册处理器
  2. 实现 ApplicationContextAware 接口,获取 Spring 应用上下文
  3. 使用 Map 存储不同类型的处理器
  4. 提供根据类型获取处理器的方法

2.3 优点

  • 对注册过程有精细化控制
  • 可以添加自定义的注册逻辑
  • 灵活性高

3. 方案二: 自动注入策略模式

3.1 定义策略接口

java 复制代码
public interface CalculateHandler {
    // 获取处理类型
    String getType();
    
    // 具体计算方法
    double calculate(double a, double b);
}

3.2 实现具体策略

java 复制代码
@Component
public class AddCalculateHandler implements CalculateHandler {
    @Override
    public String getType() {
        return "add";
    }

    @Override
    public double calculate(double a, double b) {
        return a + b;
    }
}

@Component
public class SubtractCalculateHandler implements CalculateHandler {
    @Override
    public String getType() {
        return "subtract";
    }

    @Override
    public double calculate(double a, double b) {
        return a - b;
    }
}

3.3 策略管理服务

java 复制代码
@Service
public class CalculateService {
    @Autowired
    private Map<String, CalculateHandler> calculateHandlerMap;

    public double calculate(String type, double a, double b) {
        CalculateHandler handler = calculateHandlerMap.get(type);
        if (handler == null) {
            throw new IllegalArgumentException("未找到对应的计算处理器");
        }
        return handler.calculate(a, b);
    }
}

3.4 工作原理详解

3.4.1 自动注册机制

当使用 @Autowired Map<String, Interface> 时,Spring 会:

  • 扫描所有实现指定接口的 Bean
  • 使用 Bean 名称作为 Map 的 Key
  • 使用 Bean 实例作为 Map 的 Value
3.4.2 Bean 名称规则
  • 默认使用类名首字母小写作为 Bean 名称
  • 可以通过 @Component("customName") 自定义 Bean 名称

4. 高级用法

4.1 按优先级排序

java 复制代码
@Service
public class CalculateService {
    @Autowired
    private Map<String, CalculateHandler> calculateHandlerMap;

    // 按照 @Order 注解排序
    @Autowired
    private List<CalculateHandler> calculateHandlerList;
}

4.2 自定义 Key 获取

java 复制代码
@Service
public class CalculateService {
    @Autowired
    private Map<String, CalculateHandler> calculateHandlerMap;

    // 使用自定义方法获取 Key
    public double calculate(String type, double a, double b) {
        CalculateHandler handler = calculateHandlerMap.values().stream()
            .filter(h -> h.getType().equals(type))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("未找到处理器"));
        
        return handler.calculate(a, b);
    }
}

5. 两种方案对比

特性 手动注册 自动注入
代码复杂度 较高 较低
灵活性
初始化控制 精细 简单
性能 略低 略高

6. 优点和适用场景

6.1 优点

  1. 代码解耦
  2. 动态扩展
  3. 无需手动维护注册表
  4. 充分利用 Spring 依赖注入机制

6.2 适用场景

  • 策略模式
  • 插件化开发
  • 可插拔的业务处理器
  • 系统扩展性要求高的场景

7. 注意事项

  1. 保证 Bean 名称唯一性
  2. 接口设计要合理
  3. 做好异常处理
  4. 考虑性能和扩展性

8. 最佳实践

  1. 保持接口简洁明了
  2. 明确定义每个策略的职责
  3. 合理设计方法签名
  4. 添加必要的异常处理
  5. 考虑性能和扩展性

结论

通过 Spring 的依赖注入和自动装配机制,我们可以非常优雅地实现策略模式,使代码更加灵活、可读和可维护。选择合适的实现方式,需要根据具体的业务场景和系统架构来权衡。

相关推荐
YuTaoShao1 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw2 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨2 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
双力臂4042 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
心之语歌3 小时前
Spring AI MCP 客户端
人工智能·spring·github
Edingbrugh.南空3 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
QQ_4376643143 小时前
C++11 右值引用 Lambda 表达式
java·开发语言·c++
永卿0013 小时前
设计模式-迭代器模式
java·设计模式·迭代器模式
誰能久伴不乏3 小时前
Linux如何执行系统调用及高效执行系统调用:深入浅出的解析
java·服务器·前端
慕y2744 小时前
Java学习第七十二部分——Zookeeper
java·学习·java-zookeeper