AI摘要

文章以电商折扣计算为例,展示用策略模式替代臃肿if-else:定义DiscountStrategy接口,各等级实现类自封装规则;Spring自动注入列表,工厂按userLevel匹配策略。重构后新增等级零改动原代码,职责单一、测试便利,符合开闭原则。
面对需求中越来越多的“类型”,if-else分支无限膨胀,代码难以阅读、测试和维护。本文分享我如何使用策略模式,将一段处理不同用户等级折扣的“屎山”代码,重构得清晰、优雅且易于扩展。
  1. “屎山”代码现身说法
  • ​业务背景:​​ 电商系统的折扣计算,不同用户等级(普通、白银、黄金、钻石)享受不同的折扣。
  • 重构前的代码(典型的面向过程编程):
@Service
public class DiscountService {

    public BigDecimal calculateDiscount(String userLevel, BigDecimal originalPrice) {
        // 等级校验
        if (userLevel == null) {
            throw new IllegalArgumentException("用户等级不能为空");
        }
        // 庞大的if-else分支
        if ("NORMAL".equals(userLevel)) {
            return originalPrice.multiply(new BigDecimal("0.99"));
        } else if ("SILVER".equals(userLevel)) {
            return originalPrice.multiply(new BigDecimal("0.95"));
        } else if ("GOLD".equals(userLevel)) {
            // 黄金会员可能有额外的满减逻辑,让代码更混乱
            BigDecimal discountedPrice = originalPrice.multiply(new BigDecimal("0.90"));
            if (discountedPrice.compareTo(new BigDecimal("100")) > 0) {
                discountedPrice = discountedPrice.subtract(new BigDecimal("10"));
            }
            return discountedPrice;
        } else if ("DIAMOND".equals(userLevel)) {
            return originalPrice.multiply(new BigDecimal("0.85"));
        } else {
            throw new IllegalArgumentException("不支持的会员等级: " + userLevel);
        }
    }
}
  • 痛点分析:

    • ​违反开闭原则:​​ 新增一个“王者”会员等级,必须修改这个核心方法,容易引入Bug。
    • ​可读性差:​​ 方法冗长,各个等级的逻辑耦合在一起。
    • ​可测试性差:​​ 很难为每个等级的逻辑编写独立的单元测试。
    • ​职责不清:​​ 一个方法承担了所有等级的计算逻辑。
  • 重构实施:策略模式登场

    • ​第一步:定义策略接口。​​ 抽象出折扣计算的共同行为。
/**
 * 折扣策略接口
 */
public interface DiscountStrategy {
    /**
     * 判断该策略是否支持给定的用户等级
     */
    boolean supports(String userLevel);

    /**
     * 计算折扣价
     * @param originalPrice 原价
     * @return 折扣后的价格
     */
    BigDecimal apply(BigDecimal originalPrice);
}

​第二步:实现具体策略类。​​ 每个等级一个类,职责单一。

/**
 * 普通会员策略
 */
@Component // 关键:让Spring管理成为Bean
public class NormalDiscountStrategy implements DiscountStrategy {
    @Override
    public boolean supports(String userLevel) {
        return "NORMAL".equals(userLevel);
    }
    @Override
    public BigDecimal apply(BigDecimal originalPrice) {
        return originalPrice.multiply(new BigDecimal("0.99"));
    }
}

/**
 * 黄金会员策略(包含复杂逻辑)
 */
@Component
public class GoldDiscountStrategy implements DiscountStrategy {
    @Override
    public boolean supports(String userLevel) {
        return "GOLD".equals(userLevel);
    }
    @Override
    public BigDecimal apply(BigDecimal originalPrice) {
        BigDecimal discountedPrice = originalPrice.multiply(new BigDecimal("0.90"));
        // 黄金会员的专属满减逻辑被隔离在此
        if (discountedPrice.compareTo(new BigDecimal("100")) > 0) {
            discountedPrice = discountedPrice.subtract(new BigDecimal("10"));
        }
        return discountedPrice;
    }
}
// ... 其他策略类类似

​第三步:创建策略工厂(核心)。​​ 利用Spring的依赖注入,自动收集所有策略。

@Component
public class DiscountStrategyFactory {

    // Spring会自动将DiscountStrategy的所有实现类注入到这个List中
    private final List<DiscountStrategy> strategies;

    // 构造器注入
    public DiscountStrategyFactory(List<DiscountStrategy> strategies) {
        this.strategies = strategies;
    }

    /**
     * 根据用户等级获取对应的策略
     */
    public DiscountStrategy getStrategy(String userLevel) {
        return strategies.stream()
                .filter(s -> s.supports(userLevel))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("不支持的会员等级: " + userLevel));
    }
}

​第四步:重构核心服务类。​​ 变得极其简洁。

@Service
public class DiscountService {

    private final DiscountStrategyFactory factory;

    // 构造器注入工厂
    public DiscountService(DiscountStrategyFactory factory) {
        this.factory = factory;
    }

    public BigDecimal calculateDiscount(String userLevel, BigDecimal originalPrice) {
        // 1. 参数校验(可选,也可放在策略中)
        if (userLevel == null) {
            throw new IllegalArgumentException("用户等级不能为空");
        }
        // 2. 通过工厂获取策略
        DiscountStrategy strategy = factory.getStrategy(userLevel);
        // 3. 执行策略
        return strategy.apply(originalPrice);
    }
}
  1. 重构后的巨大优势
  • ​符合开闭原则:​​ 新增会员等级,只需创建一个新的DiscountStrategy实现类即可。DiscountServiceDiscountStrategyFactory完全无需修改​。
  • ​代码清晰,职责分离:​​ 每个策略类只关心自己的计算逻辑,DiscountService只负责调度,代码可读性极大提升。
  • ​易于单元测试:​​ 可以轻松地单独测试GoldDiscountStrategy的复杂满减逻辑,而无需关心其他等级。
  • ​易于扩展:​​ 如果需要从数据库或配置中心加载折扣规则,只需要修改具体的策略实现类,调度逻辑不受影响。

  1. 更进一步:与工厂模式/Spring的强大结合
  • 可以不需要supports方法,而是通过注解(如@DiscountType("GOLD"))来标识策略类型,工厂通过扫描注解来建立映射关系Map<String, DiscountStrategy>,这样查找效率更高(O(1))。
版权声明 ▶ 本网站名称:黄磊的博客
▶ 本文标题:告别if-else地狱:策略模式在复杂业务逻辑中的实战重构
▶ 本文链接:https://www.huangleicole.com/backend-related/39.html
▶ 转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处!!

如果觉得我的文章对你有用,请随意赞赏