《别再写满屏的if-else了!Spring Boot + 策略模式实战优化》
哈喽,小伙伴们!今天我们来聊聊一个让很多程序员头疼的问题------满屏幕的if-else语句。相信大家都见过那种一个方法里嵌套了十几层if-else的代码吧?不仅难维护,新加一个条件还得小心翼翼。今天我就给大家带来一个超实用的解决方案:Spring Boot + 策略模式实战优化!
一、问题场景:支付业务中的if-else地狱
假设我们有个电商系统,需要支持多种支付方式:支付宝、微信支付、银联支付。很多同学可能会这样写:
csharp
@Service
public class PaymentService {
public String pay(String payType, BigDecimal amount) {
if ("alipay".equals(payType)) {
// 支付宝支付
System.out.println("使用支付宝支付:" + amount);
return "支付宝支付成功";
} else if ("wechat".equals(payType)) {
// 微信支付
System.out.println("使用微信支付:" + amount);
return "微信支付成功";
} else if ("unionpay".equals(payType)) {
// 银联支付
System.out.println("使用银联支付:" + amount);
return "银联支付成功";
} else {
throw new RuntimeException("支付方式错误");
}
}
}
看起来是不是很熟悉?如果再加个"云闪付"、"数字货币支付",这个方法就会越来越臃肿!
二、策略模式登场:优雅解决方案
2.1 什么是策略模式?
简单说,策略模式就是定义一系列算法,把它们封装起来,并且使它们可以相互替换。这样,算法的变化就不会影响到使用算法的客户端。
2.2 三步改造法
第一步:定义策略接口
arduino
public interface PaymentStrategy {
/**
* 支付类型
*/
String getType();
/**
* 支付方法
*/
String pay(BigDecimal amount);
}
第二步:实现具体策略
typescript
@Component
public class AlipayStrategy implements PaymentStrategy {
@Override
public String getType() {
return "alipay";
}
@Override
public String pay(BigDecimal amount) {
// 这里写真实的支付宝支付逻辑
System.out.println("执行支付宝支付,金额:" + amount);
return "支付宝支付成功,金额:" + amount;
}
}
@Component
public class WechatPayStrategy implements PaymentStrategy {
@Override
public String getType() {
return "wechat";
}
@Override
public String pay(BigDecimal amount) {
// 微信支付逻辑
System.out.println("执行微信支付,金额:" + amount);
return "微信支付成功,金额:" + amount;
}
}
@Component
public class UnionPayStrategy implements PaymentStrategy {
@Override
public String getType() {
return "unionpay";
}
@Override
public String pay(BigDecimal amount) {
// 银联支付逻辑
System.out.println("执行银联支付,金额:" + amount);
return "银联支付成功,金额:" + amount;
}
}
第三步:策略工厂类
typescript
@Component
public class PaymentStrategyFactory {
private final Map<String, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();
/**
* 注入所有PaymentStrategy实现
*/
public PaymentStrategyFactory(List<PaymentStrategy> strategies) {
for (PaymentStrategy strategy : strategies) {
strategyMap.put(strategy.getType(), strategy);
}
}
/**
* 获取支付策略
*/
public PaymentStrategy getStrategy(String type) {
PaymentStrategy strategy = strategyMap.get(type);
if (strategy == null) {
throw new RuntimeException("未找到对应的支付策略:" + type);
}
return strategy;
}
/**
* 获取所有支持的支付方式
*/
public Set<String> getSupportTypes() {
return strategyMap.keySet();
}
}
三、使用姿势:简洁优雅的调用
3.1 改造后的Service
typescript
@Service
public class PaymentService {
private final PaymentStrategyFactory strategyFactory;
public PaymentService(PaymentStrategyFactory strategyFactory) {
this.strategyFactory = strategyFactory;
}
public String pay(String payType, BigDecimal amount) {
PaymentStrategy strategy = strategyFactory.getStrategy(payType);
return strategy.pay(amount);
}
/**
* 获取支持的支付方式
*/
public Set<String> getSupportPayTypes() {
return strategyFactory.getSupportTypes();
}
}
3.2 Controller层示例
less
@RestController
@RequestMapping("/api/payment")
public class PaymentController {
private final PaymentService paymentService;
public PaymentController(PaymentService paymentService) {
this.paymentService = paymentService;
}
@PostMapping("/pay")
public ResponseEntity<?> pay(@RequestParam String payType,
@RequestParam BigDecimal amount) {
try {
String result = paymentService.pay(payType, amount);
return ResponseEntity.ok(result);
} catch (Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
@GetMapping("/support-types")
public ResponseEntity<?> getSupportTypes() {
return ResponseEntity.ok(paymentService.getSupportPayTypes());
}
}
四、进阶玩法:注解 + 策略模式
如果你想要更优雅,可以试试注解方式:
4.1 定义支付类型注解
less
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface PayType {
String value();
}
4.2 改造策略实现
less
@PayType("alipay")
public class AlipayStrategy implements PaymentStrategy {
// 省略具体实现
}
@PayType("wechat")
public class WechatPayStrategy implements PaymentStrategy {
// 省略具体实现
}
4.3 改造工厂类
kotlin
@Component
public class PaymentStrategyFactoryV2 {
private final Map<String, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();
/**
* 使用ApplicationContext获取所有带PayType注解的Bean
*/
public PaymentStrategyFactoryV2(ApplicationContext applicationContext) {
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(PayType.class);
beans.forEach((beanName, bean) -> {
PayType annotation = applicationContext.findAnnotationOnBean(beanName, PayType.class);
if (annotation != null && bean instanceof PaymentStrategy) {
strategyMap.put(annotation.value(), (PaymentStrategy) bean);
}
});
}
// 其他方法保持不变
}
五、测试验证
创建一个测试类验证一下:
java
csharp
@SpringBootTest
class PaymentStrategyTest {
@Autowired
private PaymentService paymentService;
@Test
void testPay() {
BigDecimal amount = new BigDecimal("100.50");
System.out.println("支持的支付方式:" + paymentService.getSupportPayTypes());
String result = paymentService.pay("alipay", amount);
System.out.println("支付结果:" + result);
result = paymentService.pay("wechat", amount);
System.out.println("支付结果:" + result);
// 测试不存在的支付方式
assertThrows(RuntimeException.class, () -> {
paymentService.pay("unknown", amount);
});
}
}
六、实际应用扩展
6.1 结合配置文件动态启用策略
markdown
# application.yml
payment:
enabled-strategies:
- alipay
- wechat
- unionpay
swift
@Component
public class DynamicPaymentStrategyFactory {
@Value("${payment.enabled-strategies}")
private List<String> enabledStrategies;
private final Map<String, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();
public DynamicPaymentStrategyFactory(List<PaymentStrategy> strategies) {
for (PaymentStrategy strategy : strategies) {
if (enabledStrategies.contains(strategy.getType())) {
strategyMap.put(strategy.getType(), strategy);
}
}
}
// 其他方法...
}
6.2 策略模式+模板方法模式组合
typescript
public abstract class AbstractPaymentStrategy implements PaymentStrategy {
@Override
public String pay(BigDecimal amount) {
// 1. 参数验证
validate(amount);
// 2. 执行支付
String transactionId = doPay(amount);
// 3. 记录日志
logPayment(transactionId, amount);
// 4. 返回结果
return buildResult(transactionId, amount);
}
protected abstract String doPay(BigDecimal amount);
protected void validate(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new RuntimeException("支付金额必须大于0");
}
}
protected void logPayment(String transactionId, BigDecimal amount) {
System.out.println("支付流水号:" + transactionId + ",金额:" + amount);
}
protected String buildResult(String transactionId, BigDecimal amount) {
return getType() + "支付成功,流水号:" + transactionId + ",金额:" + amount;
}
}
总结
优点总结:
- 开闭原则:新增支付方式只需添加新策略类,无需修改现有代码
- 可读性:代码结构清晰,职责分明
- 可维护性:每个支付逻辑独立,方便测试和修改
- 可扩展性:轻松支持动态配置、热更新等高级功能
使用场景:
- 多种相似算法或业务逻辑需要切换
- 存在大量的条件判断语句
- 系统需要动态选择不同算法
- 希望避免使用多重条件转移语句
注意事项:
- 策略数量控制:如果策略类过多,考虑使用其他模式(如责任链模式)组合使用
- 客户端感知:客户端需要知道所有策略,可以通过配置中心或枚举管理
- 性能考虑:策略模式会增加对象数量,在极端性能敏感场景需要权衡
- Spring集成:确保策略类都被Spring管理,注意Bean的加载顺序
- 默认策略:考虑提供一个默认策略,避免因策略不存在而报错
- 策略参数:如果不同策略需要不同参数,可以考虑使用Context对象封装
最后的小贴士:
策略模式不是银弹,如果你的业务逻辑很简单,只有2-3个分支,那么简单的if-else可能更合适。但是当分支超过3个,或者未来可能会增加更多分支时,策略模式的优势就会体现出来。
记住,好的代码不是一蹴而就的,而是在不断重构中逐渐变好的。当你看到满屏的if-else时,不妨想想:这里是不是可以用策略模式优化一下?
希望这篇博客能帮到你!如果有问题或更好的建议,欢迎在评论区交流讨论。我们一起写出更优雅的代码!
作者:张工摆Bug 转载请注明出处,让我们一起打造更好的技术社区!