Map+函数式接口实现策略模式

1,093 阅读4分钟

1、传统的策略模式

在项目中,策略模式是一种常用的设计模式,核心由三部分构成:

  • 接口(Strategy Interface):定义公共接口,规定每个策略类必须实现的方法,保证策略一致性;
  • 实现类(Concrete Strategies):实现策略接口,封装具体的算法或行为;
  • 上下文(Context):持有策略接口的引用,运行时动态切换和调用具体策略。

策略模式的优势在于,能将冗长的if-else/switch-case逻辑抽离到独立类中,让代码更清晰、易维护。新增或修改策略时,只需调整对应策略类,无需改动原有逻辑。

但它也有缺点:当条件分支较多时,对应的策略实现类会急剧增加,可能导致“类爆炸”,增加代码管理难度。

那么,若想抽离条件逻辑,又不想把逻辑封装在专门的策略类中,而是直接复用任意类的方法,该怎么做呢?

2、Map+函数式接口实战

借助Java 8的函数式接口(如Function)和Map,可实现更灵活的策略模式,避免类爆炸问题。核心代码如下:

private final Map<String, Function<T, R>> strategyMap = new HashMap<>();  

其中,Map的key是判断条件,value是对应的执行逻辑;Function的泛型T是方法入参类型,R是返回值类型。

业务场景

电商订单支付时,需根据用户选择的支付方式(如支付宝、微信、银联)调用不同接口处理支付。每种支付方式有独立的接口和逻辑,我们希望以“支付方式类型(payType)”为条件,根据订单信息调用对应接口完成支付。

代码实现

第一步:定义基础类和DTO
先创建订单和支付结果的载体类,用于传递数据:

// 订单信息DTO  
@Data  
public class OrderDTO {  
    private String orderNo; // 订单编号  
    private BigDecimal amount; // 支付金额  
    private String userId; // 用户ID  
    // 其他订单相关字段...  
}  

// 支付结果DTO  
@Data  
public class PaymentResultDTO {  
    private boolean success; // 支付是否成功  
    private String orderNo; // 订单编号  
    private String transactionId; // 第三方交易号  
    private String payMethod; // 支付方式  
    // 其他支付结果字段...  
}  

第二步:实现支付服务类
不同支付方式的具体逻辑,封装在各自的服务类中:

// 支付宝支付服务  
@Service  
public class AlipayService {  
    /**  
     * 支付宝支付处理  
     * @param order 订单信息  
     * @return 支付结果  
     */  
    public PaymentResultDTO processAlipay(OrderDTO order) {  
        // 调用支付宝接口处理支付(模拟)  
        System.out.println("调用支付宝接口,订单" + order.getOrderNo() + "支付中...");  
        PaymentResultDTO result = new PaymentResultDTO();  
        result.setSuccess(true);  
        result.setOrderNo(order.getOrderNo());  
        result.setPayMethod("支付宝");  
        result.setTransactionId("ALIPAY_" + System.currentTimeMillis());  
        return result;  
    }  
}  

// 微信支付服务  
@Service  
public class WechatPayService {  
    /**  
     * 微信支付处理  
     * @param order 订单信息  
     * @return 支付结果  
     */  
    public PaymentResultDTO processWechatPay(OrderDTO order) {  
        // 调用微信支付接口处理支付(模拟)  
        System.out.println("调用微信支付接口,订单" + order.getOrderNo() + "支付中...");  
        PaymentResultDTO result = new PaymentResultDTO();  
        result.setSuccess(true);  
        result.setOrderNo(order.getOrderNo());  
        result.setPayMethod("微信支付");  
        result.setTransactionId("WECHAT_" + System.currentTimeMillis());  
        return result;  
    }  
}  

// 银联支付服务  
@Service  
public class UnionPayService {  
    /**  
     * 银联支付处理  
     * @param order 订单信息  
     * @return 支付结果  
     */  
    public PaymentResultDTO processUnionPay(OrderDTO order) {  
        // 调用银联接口处理支付(模拟)  
        System.out.println("调用银联接口,订单" + order.getOrderNo() + "支付中...");  
        PaymentResultDTO result = new PaymentResultDTO();  
        result.setSuccess(true);  
        result.setOrderNo(order.getOrderNo());  
        result.setPayMethod("银联支付");  
        result.setTransactionId("UNIONPAY_" + System.currentTimeMillis());  
        return result;  
    }  
}  

第三步:用Map+函数式接口整合策略
创建支付上下文类,通过Map存储“支付方式-处理逻辑”的映射,替代if-else:

@Service  
public class PaymentContext {  
    // 存储支付方式与对应处理逻辑的映射:key=支付方式类型,value=处理方法  
    private final Map<Integer, Function<OrderDTO, PaymentResultDTO>> payStrategyMap = new HashMap<>();  

    // 注入各支付服务  
    @Resource  
    private AlipayService alipayService;  
    @Resource  
    private WechatPayService wechatPayService;  
    @Resource  
    private UnionPayService unionPayService;  

    // 初始化映射关系(替代if-else)  
    public PaymentContext() {  
        // 支付宝(支付类型1)  
        payStrategyMap.put(1, order -> alipayService.processAlipay(order));  
        // 微信支付(支付类型2)  
        payStrategyMap.put(2, order -> wechatPayService.processWechatPay(order));  
        // 银联支付(支付类型3)  
        payStrategyMap.put(3, order -> unionPayService.processUnionPay(order));  
    }  

    // 根据支付类型处理支付  
    public PaymentResultDTO processPayment(Integer payType, OrderDTO order) {  
        // 从map中获取对应策略  
        Function<OrderDTO, PaymentResultDTO> payFunction = payStrategyMap.get(payType);  
        // 执行策略并返回结果(处理未匹配的支付类型)  
        return Optional.ofNullable(payFunction)  
                .map(func -> func.apply(order))  
                .orElseThrow(() -> new IllegalArgumentException("不支持的支付方式:" + payType));  
    }  
}  

核心逻辑说明

  • payStrategyMap存储“支付类型-处理方法”的映射:key是支付类型(1=支付宝、2=微信、3=银联),value是对应的处理方法(如alipayService::processAlipay)。
  • 当需要处理支付时,只需通过payType从map中获取对应方法,直接调用即可,无需if-else判断。

3、总结

相比传统策略模式,Map+函数式接口的实现有明显优势:

  1. 避免类爆炸:无需为每个策略创建独立类,直接复用现有服务类的方法;
  2. 代码更简洁:用map的key-value映射替代冗长的if-else,逻辑更清晰;
  3. 扩展性更强:新增支付方式时,只需添加服务类方法,并在map中注册,无需修改原有代码;
  4. 维护更方便:所有策略映射集中在map初始化处,便于统一管理。

通过使用 Map 和函数式接口,我们可以更加灵活地实现策略模式,避免了传统策略模式中因大量 if-else 或 switch-case 语句而导致的代码复杂性。这种方法不仅使代码更加简洁和可读,还提高了代码的可扩展性和可维护性。