策略工厂模式(Factory Pattern)

82 阅读4分钟

我来分享一个在电商系统中非常实用的策略模式应用场景:多种支付方式的选择与扩展

场景描述

在电商系统中,用户可以选择不同的支付方式(微信支付、支付宝、银行卡支付等),每种支付方式有不同的处理逻辑,但对外提供统一的支付接口。

实现方案

1. 定义支付策略接口

java

public interface PaymentStrategy {
    /**
     * 支付
     * @param amount 支付金额
     * @param paymentRequest 支付请求参数
     * @return 支付结果
     */
    PaymentResult pay(BigDecimal amount, PaymentRequest paymentRequest);
    
    /**
     * 支持的支付类型
     */
    PaymentType getPaymentType();
}

// 支付类型枚举
public enum PaymentType {
    WECHAT_PAY("微信支付"),
    ALIPAY("支付宝"),
    BANK_CARD("银行卡支付"),
    WALLET("钱包支付");
    
    private final String description;
    
    PaymentType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

2. 实现具体的支付策略

微信支付策略:

java

@Component
public class WechatPayStrategy implements PaymentStrategy {
    
    @Autowired
    private WechatPayService wechatPayService;
    
    @Override
    public PaymentResult pay(BigDecimal amount, PaymentRequest paymentRequest) {
        // 微信支付的具体逻辑
        WechatPayRequest wechatRequest = buildWechatRequest(amount, paymentRequest);
        return wechatPayService.pay(wechatRequest);
    }
    
    @Override
    public PaymentType getPaymentType() {
        return PaymentType.WECHAT_PAY;
    }
    
    private WechatPayRequest buildWechatRequest(BigDecimal amount, PaymentRequest request) {
        // 构建微信支付请求参数
        return new WechatPayRequest(amount, request.getOpenId(), request.getOrderNo());
    }
}

支付宝策略:

java

@Component
public class AlipayStrategy implements PaymentStrategy {
    
    @Autowired
    private AlipayService alipayService;
    
    @Override
    public PaymentResult pay(BigDecimal amount, PaymentRequest paymentRequest) {
        // 支付宝的具体逻辑
        AlipayRequest alipayRequest = buildAlipayRequest(amount, paymentRequest);
        return alipayService.pay(alipayRequest);
    }
    
    @Override
    public PaymentType getPaymentType() {
        return PaymentType.ALIPAY;
    }
    
    private AlipayRequest buildAlipayRequest(BigDecimal amount, PaymentRequest request) {
        return new AlipayRequest(amount, request.getUserId(), request.getOrderNo());
    }
}

银行卡支付策略:

java

@Component
public class BankCardPayStrategy implements PaymentStrategy {
    
    @Autowired
    private BankCardService bankCardService;
    
    @Override
    public PaymentResult pay(BigDecimal amount, PaymentRequest paymentRequest) {
        // 银行卡支付的具体逻辑
        BankCardRequest bankRequest = buildBankCardRequest(amount, paymentRequest);
        return bankCardService.pay(bankRequest);
    }
    
    @Override
    public PaymentType getPaymentType() {
        return PaymentType.BANK_CARD;
    }
    
    private BankCardRequest buildBankCardRequest(BigDecimal amount, PaymentRequest request) {
        return new BankCardRequest(amount, request.getCardNo(), 
                                 request.getCvv(), request.getExpireDate());
    }
}

3. 策略工厂管理所有策略

java

@Component
public class PaymentStrategyFactory {
    
    private final Map<PaymentType, PaymentStrategy> strategyMap;
    
    @Autowired
    public PaymentStrategyFactory(List<PaymentStrategy> strategies) {
        strategyMap = strategies.stream()
                .collect(Collectors.toMap(
                    PaymentStrategy::getPaymentType, 
                    Function.identity()
                ));
    }
    
    /**
     * 根据支付类型获取对应的策略
     */
    public PaymentStrategy getStrategy(PaymentType paymentType) {
        PaymentStrategy strategy = strategyMap.get(paymentType);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
        }
        return strategy;
    }
    
    /**
     * 获取所有支持的支付类型
     */
    public List<PaymentType> getSupportedPaymentTypes() {
        return new ArrayList<>(strategyMap.keySet());
    }
}

4. 支付服务类(上下文)

java

@Service
public class PaymentService {
    
    @Autowired
    private PaymentStrategyFactory strategyFactory;
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private PaymentRecordService paymentRecordService;
    
    /**
     * 执行支付
     */
    public PaymentResult executePayment(PaymentRequest request) {
        // 1. 验证订单状态
        Order order = orderService.validateOrder(request.getOrderNo());
        
        // 2. 根据支付类型获取对应的策略
        PaymentStrategy strategy = strategyFactory.getStrategy(request.getPaymentType());
        
        // 3. 执行支付
        PaymentResult result = strategy.pay(order.getAmount(), request);
        
        // 4. 记录支付结果
        paymentRecordService.recordPayment(request, result);
        
        return result;
    }
    
    /**
     * 获取支持的支付方式列表
     */
    public List<PaymentType> getSupportedPayments() {
        return strategyFactory.getSupportedPaymentTypes();
    }
}

5. 控制器层

java

@RestController
@RequestMapping("/api/payment")
public class PaymentController {
    
    @Autowired
    private PaymentService paymentService;
    
    /**
     * 发起支付
     */
    @PostMapping("/pay")
    public ResponseEntity<PaymentResult> pay(@RequestBody @Valid PaymentRequest request) {
        PaymentResult result = paymentService.executePayment(request);
        return ResponseEntity.ok(result);
    }
    
    /**
     * 获取支持的支付方式
     */
    @GetMapping("/supported-methods")
    public ResponseEntity<List<PaymentType>> getSupportedPayments() {
        List<PaymentType> paymentTypes = paymentService.getSupportedPayments();
        return ResponseEntity.ok(paymentTypes);
    }
}

6. 相关DTO定义

java

// 支付请求参数
@Data
public class PaymentRequest {
    @NotBlank
    private String orderNo;
    
    @NotNull
    private PaymentType paymentType;
    
    private String openId;        // 微信支付需要
    private String userId;        // 支付宝需要
    private String cardNo;        // 银行卡支付需要
    private String cvv;           // 银行卡支付需要
    private String expireDate;    // 银行卡支付需要
}

// 支付结果
@Data
public class PaymentResult {
    private boolean success;
    private String transactionId;
    private String message;
    private BigDecimal amount;
    private LocalDateTime payTime;
}

策略模式的优势

  1. 开闭原则:新增支付方式时,只需新增一个策略实现类,无需修改现有代码
  2. 单一职责:每种支付逻辑独立封装在自己的策略类中
  3. 易于测试:可以单独测试每个策略

问题:

 @Autowired
    public PaymentStrategyFactory(List<PaymentStrategy> strategies) {
        strategyMap = strategies.stream()
                .collect(Collectors.toMap(
                    PaymentStrategy::getPaymentType, 
                    Function.identity()
                ));
    }
    哪里传递参数了

您指出了一个很好的问题!这里确实没有显式传递参数,让我解释一下Spring是如何工作的:

Spring的依赖注入机制

在Spring中,当使用@Autowired注解构造函数时,Spring会自动从IoC容器中查找所有匹配类型的Bean,并作为参数注入。

具体过程:

  1. 自动收集所有实现:Spring会自动找到所有实现了PaymentStrategy接口的Bean

    • WechatPayStrategy (被@Component标注)
    • AlipayStrategy (被@Component标注)
    • BankCardPayStrategy (被@Component标注)
  2. 构建List:Spring将这些Bean组装成一个List<PaymentStrategy>

  3. 注入构造函数:Spring调用构造函数时自动传递这个List

等价的手动写法:

java

// Spring在底层做的类似于:
List<PaymentStrategy> strategies = Arrays.asList(
    new WechatPayStrategy(),
    new AlipayStrategy(), 
    new BankCardPayStrategy()
);

PaymentStrategyFactory factory = new PaymentStrategyFactory(strategies);

验证这个机制:

您可以添加一个调试方法来验证:

java

@Component
public class PaymentStrategyFactory {
    
    private final Map<PaymentType, PaymentStrategy> strategyMap;
    
    @Autowired
    public PaymentStrategyFactory(List<PaymentStrategy> strategies) {
        // 打印看看Spring自动注入了哪些策略
        System.out.println("Spring自动注入的策略列表:");
        strategies.forEach(strategy -> 
            System.out.println("- " + strategy.getClass().getSimpleName())
        );
        
        strategyMap = strategies.stream()
                .collect(Collectors.toMap(
                    PaymentStrategy::getPaymentType, 
                    Function.identity()
                ));
    }
    
    // 其他方法...
}

运行时会输出:

text

Spring自动注入的策略列表:
- WechatPayStrategy
- AlipayStrategy  
- BankCardPayStrategy

如果还是不清楚,可以显式配置:

java

@Configuration
public class PaymentConfig {
    
    @Bean
    @Autowired
    public PaymentStrategyFactory paymentStrategyFactory(
            WechatPayStrategy wechatPayStrategy,
            AlipayStrategy alipayStrategy,
            BankCardPayStrategy bankCardPayStrategy) {
        
        List<PaymentStrategy> strategies = Arrays.asList(
            wechatPayStrategy,
            alipayStrategy, 
            bankCardPayStrategy
        );
        
        return new PaymentStrategyFactory(strategies);
    }
}

但第一种方式更简洁,是Spring推荐的写法。

总结

Spring的@Autowired + 构造函数参数机制会自动:

  1. 扫描所有PaymentStrategy实现类
  2. 实例化并注册到IoC容器
  3. 组装成List注入到构造函数

这就是为什么我们不需要显式传递参数的原因!