springboot策略设计模式最佳实践

假设我们希望实现以下需求:

  1. 支付方式(如支付宝、微信支付)可以动态切换。
  2. 支付方式配置从配置文件中加载,或者支持在数据库中动态更新。
  3. 配置文件或数据库中指定当前生效的支付方式。

步骤 1: 配置文件定义支付方式

我们可以在 application.ymlapplication.properties 中定义支付方式配置项,指定默认的支付方式。

# application.yml
payment:
  defaultMethod: alipay

这里我们定义了一个 payment.defaultMethod 配置项,它用于指定当前选择的支付方式。假设我们有多个支付方式,默认支付方式是 alipay

步骤 2: 在 PaymentContext 中加载动态配置

为了根据配置动态选择支付方式,我们需要将配置文件中的 defaultMethod 读入,并根据它来确定使用哪个支付策略。可以通过 Spring 的 @Value 注解来注入配置项。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Map;

@Service
public class PaymentContext {

    private final Map<String, PaymentStrategy> paymentStrategies;
    
    @Value("${payment.defaultMethod}")
    private String defaultPaymentMethod;

    public PaymentContext(Map<String, PaymentStrategy> paymentStrategies) {
        this.paymentStrategies = paymentStrategies;
    }

    public void executePayment(double amount) {
        // 根据配置的支付方式动态选择策略
        PaymentStrategy strategy = paymentStrategies.get(defaultPaymentMethod);
        if (strategy != null) {
            strategy.pay(amount);
        } else {
            throw new IllegalArgumentException("Invalid payment method: " + defaultPaymentMethod);
        }
    }
}

在这个 PaymentContext 中,我们通过 @Value 注解将 application.yml 中的 payment.defaultMethod 配置项注入到 defaultPaymentMethod 变量中。然后在 executePayment 方法中,根据配置项选择对应的支付策略执行支付。

步骤 3: 动态更新支付方式(可选)

如果您希望在运行时动态切换支付方式,可以考虑将支付方式配置存储在数据库中。通过查询数据库中的配置项,可以灵活地更新支付方式。

假设我们有一个 PaymentConfig 表,包含 method_codeenabled 等字段来表示当前生效的支付方式。

@Entity
public class PaymentConfig {
    @Id
    private Long id;
    private String methodCode;
    private Boolean enabled;

    // getters and setters
}

接着,可以通过 Spring Data JPA 访问数据库中的配置:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class DynamicPaymentConfigService {

    private final PaymentConfigRepository paymentConfigRepository;

    @Autowired
    public DynamicPaymentConfigService(PaymentConfigRepository paymentConfigRepository) {
        this.paymentConfigRepository = paymentConfigRepository;
    }

    public String getActivePaymentMethod() {
        List<PaymentConfig> activeConfigs = paymentConfigRepository.findByEnabled(true);
        // 假设返回第一个启用的支付方式
        if (!activeConfigs.isEmpty()) {
            return activeConfigs.get(0).getMethodCode();
        }
        return null; // 如果没有配置,返回空
    }
}

然后在 PaymentContext 中使用这个动态配置服务来更新支付方式:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;

@Service
public class PaymentContext {

    private final Map<String, PaymentStrategy> paymentStrategies;
    private final DynamicPaymentConfigService dynamicPaymentConfigService;

    @Autowired
    public PaymentContext(Map<String, PaymentStrategy> paymentStrategies, DynamicPaymentConfigService dynamicPaymentConfigService) {
        this.paymentStrategies = paymentStrategies;
        this.dynamicPaymentConfigService = dynamicPaymentConfigService;
    }

    public void executePayment(double amount) {
        // 从数据库或配置中获取当前启用的支付方式
        String activePaymentMethod = dynamicPaymentConfigService.getActivePaymentMethod();
        if (activePaymentMethod != null) {
            PaymentStrategy strategy = paymentStrategies.get(activePaymentMethod);
            if (strategy != null) {
                strategy.pay(amount);
            } else {
                throw new IllegalArgumentException("Invalid payment method: " + activePaymentMethod);
            }
        } else {
            throw new IllegalStateException("No active payment method configured.");
        }
    }
}

通过上述方式,我们可以从数据库动态获取当前启用的支付方式,并在执行支付时应用它。

步骤 4: 控制器调用(不暴露支付方式)

在控制器层面,我们依然只关心执行支付,而不会暴露具体的支付方式。支付方式的选择完全依赖于配置文件或数据库中的设置。

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/payment")
public class PaymentController {

    private final PaymentContext paymentContext;

    @Autowired
    public PaymentController(PaymentContext paymentContext) {
        this.paymentContext = paymentContext;
    }

    @PostMapping("/pay")
    public String pay(@RequestParam double amount) {
        try {
            paymentContext.executePayment(amount);
            return "支付成功!";
        } catch (IllegalArgumentException | IllegalStateException e) {
            return e.getMessage();
        }
    }
}

总结

  • 动态配置:通过 application.yml 或数据库存储支付方式配置,能够动态切换支付方式而不暴露给前端请求 URL。
  • 灵活扩展:新增支付方式时,只需要实现一个新的支付策略类,并在配置文件或数据库中添加相应的配置,无需修改控制器或核心业务逻辑。
  • 安全性:通过不暴露支付方式具体实现,只提供支付功能接口,增加了安全性和封装性。

这种设计不仅能够支持多种支付方式,还能够根据配置灵活切换支付策略,适应不同的支付场景。

posted @ 2024-11-07 22:27  唐钰逍遥  阅读(157)  评论(0)    收藏  举报