《别再写满屏的if-else了!Spring Boot + 策略模式实战优化》

《别再写满屏的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;
    }
}

总结

优点总结:

  1. 开闭原则:新增支付方式只需添加新策略类,无需修改现有代码
  2. 可读性:代码结构清晰,职责分明
  3. 可维护性:每个支付逻辑独立,方便测试和修改
  4. 可扩展性:轻松支持动态配置、热更新等高级功能

使用场景:

  • 多种相似算法或业务逻辑需要切换
  • 存在大量的条件判断语句
  • 系统需要动态选择不同算法
  • 希望避免使用多重条件转移语句

注意事项:

  1. 策略数量控制:如果策略类过多,考虑使用其他模式(如责任链模式)组合使用
  2. 客户端感知:客户端需要知道所有策略,可以通过配置中心或枚举管理
  3. 性能考虑:策略模式会增加对象数量,在极端性能敏感场景需要权衡
  4. Spring集成:确保策略类都被Spring管理,注意Bean的加载顺序
  5. 默认策略:考虑提供一个默认策略,避免因策略不存在而报错
  6. 策略参数:如果不同策略需要不同参数,可以考虑使用Context对象封装

最后的小贴士:

策略模式不是银弹,如果你的业务逻辑很简单,只有2-3个分支,那么简单的if-else可能更合适。但是当分支超过3个,或者未来可能会增加更多分支时,策略模式的优势就会体现出来。

记住,好的代码不是一蹴而就的,而是在不断重构中逐渐变好的。当你看到满屏的if-else时,不妨想想:这里是不是可以用策略模式优化一下?

希望这篇博客能帮到你!如果有问题或更好的建议,欢迎在评论区交流讨论。我们一起写出更优雅的代码!


作者:张工摆Bug 转载请注明出处,让我们一起打造更好的技术社区!

相关推荐
断剑zou天涯2 小时前
【算法笔记】AC自动机
java·笔记·算法
独自归家的兔2 小时前
基于GUI-PLUS 搭配 Java Robot 实现智能桌面操控
java·开发语言·人工智能
用户3721574261352 小时前
Python 实现 PDF 文档压缩:完整指南
java
ew452182 小时前
【JAVA】实现word的DOCX/DOC文档内容替换、套打、支持表格内容替换。
java·开发语言·word
贺今宵2 小时前
装Maven并在idea上配置
java·maven·intellij-idea
qq_12498707532 小时前
基于springboot的幼儿园家校联动小程序的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·spring·微信小程序·小程序
Alsn862 小时前
27.IDEA 专业版创建与打包 Java 命令行程序
java·ide·intellij-idea
毕设源码-郭学长2 小时前
【开题答辩全过程】以 基于JAVA的车辆违章信息管理系统设计及实现为例,包含答辩的问题和答案
java·开发语言
while(1){yan}2 小时前
UDP和TCP的核心
java·开发语言·网络·网络协议·tcp/ip·udp