
在系统(如交易、清算、账户系统)中,我们经常会遇到这样的需求:
"同一个入口,根据不同的交易类型执行不同的逻辑。"
例如:
- 交易簿记(TRADE_BOOKING)
- 冲销交易(TRADE_REVERSAL)
- 查询交易详情(TRADE_DETAIL)
如果我们用 if-else
或 switch
来写,会非常臃肿、难维护。
本文将带你从最初的 枚举多态写法 ,一步步演进到 Spring Boot 自动注册策略模式 ,
打造一套既优雅又实用的分发机制。
一、第一阶段:枚举多态(Enum Strategy Pattern)
最经典、最简洁的写法:
java
public enum TradeOperationType {
TRADE_BOOKING {
@Override
public Response handle(Request req) {
// 实现交易簿记逻辑
}
},
TRADE_DETAIL {
@Override
public Response handle(Request req) {
// 实现交易详情逻辑
}
};
public abstract Response handle(Request req);
}
✅ 优势
优点 | 说明 |
---|---|
类型安全 | 枚举替代字符串常量,编译期校验 |
结构清晰 | 每个常量实现自己逻辑,天然多态 |
无需工厂 | 枚举自带单例和分发能力 |
扩展方便 | 新增逻辑只需加一个枚举常量 |
⚠️ 局限
缺点 | 说明 |
---|---|
不适合复杂逻辑 | 逻辑太多会让枚举类臃肿 |
不支持依赖注入 | 无法使用 Spring Bean |
不可运行时扩展 | 枚举在编译期固定 |
不方便单元测试 | 不易 Mock 或替换实现 |
🎯 适用场景
- 策略数量少(≤10 个)
- 逻辑简单且稳定
👉 如固定的交易状态、核算规则、简单风控判断。
二、第二阶段:枚举 + 策略接口(更解耦)
当逻辑逐渐复杂,可以把实现抽离出去:
java
public interface TradeStrategy {
Response handle(Request req);
}
public class TradeBookingStrategy implements TradeStrategy {
public Response handle(Request req) { ... }
}
public class TradeDetailStrategy implements TradeStrategy {
public Response handle(Request req) { ... }
}
public enum TradeOperationType {
TRADE_BOOKING(new TradeBookingStrategy()),
TRADE_DETAIL(new TradeDetailStrategy());
private final TradeStrategy strategy;
TradeOperationType(TradeStrategy strategy) {
this.strategy = strategy;
}
public Response handle(Request req) {
return strategy.handle(req);
}
}
✅ 优势
- 每种策略独立类,易维护;
- 结构更清晰;
- 支持单测与扩展。
⚠️ 缺点
- 类文件较多;
- 仍为静态注册;
- 不能动态注入 Bean。
三、第三阶段:函数式写法(Lambda 简化)
轻量策略可以直接用 Lambda:
java
public enum TradeOperationType {
TRADE_BOOKING(req -> bookTrade(req)),
TRADE_DETAIL(req -> queryDetail(req));
private final Function<Request, Response> function;
TradeOperationType(Function<Request, Response> function) {
this.function = function;
}
public Response handle(Request req) {
return function.apply(req);
}
}
✅ 优势
- 简洁;
- 无需额外类;
- 适合轻逻辑(如状态计算、类型映射)。
⚠️ 缺点
- 不适合长逻辑;
- 不易调试与扩展。
四、第四阶段:注册中心(支持动态扩展)
我们希望运行时注册不同策略:
java
public class TradeStrategyRegistry {
private static final Map<TradeOperationType, TradeStrategy> STRATEGIES =
new EnumMap<>(TradeOperationType.class);
public static void register(TradeOperationType type, TradeStrategy strategy) {
STRATEGIES.put(type, strategy);
}
public static Response execute(TradeOperationType type, Request req) {
return STRATEGIES.get(type).handle(req);
}
}
注册:
java
TradeStrategyRegistry.register(TradeOperationType.TRADE_DETAIL, new TradeDetailStrategy());
✅ 优势
- 可运行时注册;
- 解耦策略实现;
- 支持注入外部依赖。
⚠️ 缺点
- 手动注册略繁琐;
- 注册管理需规范。
五、第五阶段:Spring Boot 自动注册策略(企业级方案)
在金融核心系统中,我们更希望:
- 策略可被自动识别;
- 无需手动注册;
- 可注入 Service、DAO;
- 新增策略无需改框架代码。
于是我们引入自动注册机制👇
1️⃣ 定义枚举
java
public enum TradeOperationType {
TRADE_BOOKING,
TRADE_DETAIL,
TRADE_REVERSAL
}
2️⃣ 策略接口
java
@FunctionalInterface
public interface TradeStrategy {
Response handle(Request req);
}
3️⃣ 自定义注解
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TradeHandler {
TradeOperationType value();
}
4️⃣ 策略注册中心
java
@Component
public class TradeStrategyRegistry {
private final Map<TradeOperationType, TradeStrategy> STRATEGIES = new EnumMap<>(TradeOperationType.class);
public void register(TradeOperationType type, TradeStrategy strategy) {
STRATEGIES.put(type, strategy);
}
public Response execute(TradeOperationType type, Request req) {
TradeStrategy strategy = STRATEGIES.get(type);
if (strategy == null) throw new IllegalArgumentException("No strategy for: " + type);
return strategy.handle(req);
}
}
5️⃣ 自动扫描注册器
java
@Component
public class TradeStrategyAutoRegistrar {
@Autowired
private ApplicationContext context;
@Autowired
private TradeStrategyRegistry registry;
@PostConstruct
public void registerAll() {
Map<String, Object> beans = context.getBeansWithAnnotation(TradeHandler.class);
beans.values().forEach(bean -> {
if (bean instanceof TradeStrategy strategy) {
TradeHandler annotation = bean.getClass().getAnnotation(TradeHandler.class);
registry.register(annotation.value(), strategy);
}
});
System.out.println("已注册交易策略数量: " + beans.size());
}
}
6️⃣ 策略实现类
java
@TradeHandler(TradeOperationType.TRADE_BOOKING)
@Component
public class TradeBookingHandler implements TradeStrategy {
@Override
public Response handle(Request req) {
return new Response("Trade booked successfully");
}
}
@TradeHandler(TradeOperationType.TRADE_DETAIL)
@Component
public class TradeDetailHandler implements TradeStrategy {
@Override
public Response handle(Request req) {
return new Response("Trade detail data");
}
}
7️⃣ 使用方式
java
@Autowired
private TradeStrategyRegistry registry;
Response res = registry.execute(TradeOperationType.TRADE_DETAIL, req);
六、对比总结表
方案 | 简洁性 | 可扩展性 | 可依赖注入 | 运行时扩展 | 推荐场景 |
---|---|---|---|---|---|
枚举多态 | ⭐⭐⭐⭐ | ⭐⭐ | ❌ | ❌ | 固定逻辑、快速实现 |
枚举 + 策略接口 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ | ❌ | 逻辑较复杂 |
函数式(Lambda) | ⭐⭐⭐⭐ | ⭐⭐ | ❌ | ❌ | 轻量逻辑映射 |
枚举 + 注册中心 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ | ✅ | 可动态注册策略 |
自动注册版(Spring) | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ | ✅ | 企业金融系统推荐 |
七、总结与最佳实践
- 策略少、逻辑简单 → 枚举多态足够;
- 策略多且逻辑复杂 → 使用策略接口;
- 希望自动化管理、注入 Bean、支持扩展 → 自动注册方案最优。
✅ 在真实金融系统中(例如清算系统、账户子系统、交易记账引擎),
自动注册策略这种结构几乎是标配。
未来当有新交易类型时,只需:
java
@TradeHandler(TradeOperationType.TRADE_NETTING)
@Component
public class TradeNettingHandler implements TradeStrategy { ... }
系统自动注册,无需改动任何核心代码。
这才是"稳定与扩展"并存的架构之美。
💡 本文代码示例适用于 Spring Boot 3.x / Java 17+