干掉卫语句:用策略模式重构嵌套地狱的实战指南策略模式

1. 环境准备:一个真实的嵌套地狱案例

假设你维护一个支付路由服务,现有代码里有这样一段逻辑:根据订单类型、金额和用户等级计算手续费。原始实现用了一堆if-elseswitch,层层嵌套,可读性极差。为演示重构,我们先搭建最小Java环境:JDK 11+,任意IDE,以及一个Maven项目。核心类如下:

复制代码
// OrderType 枚举:NORMAL, PREMIUM, SUBSCRIPTION
// UserLevel 枚举:BRONZE, SILVER, GOLD, PLATINUM
public class FeeCalculator {
    public double calculate(Order order) {
        double fee = 0.0;
        if (order.getType() == OrderType.NORMAL) {
            if (order.getAmount() < 100) {
                fee = 1.0;
            } else {
                fee = 0.5;
            }
        } else if (order.getType() == OrderType.PREMIUM) {
            if (order.getUserLevel() == UserLevel.GOLD) {
                fee = 0.0;
            } else if (order.getUserLevel() == UserLevel.PLATINUM) {
                fee = 0.0;
            } else {
                fee = 0.3;
            }
        } else if (order.getType() == OrderType.SUBSCRIPTION) {
            // 更多嵌套...
            fee = 0.2;
        }
        // 还有更多else if...
        return fee;
    }
}

这段代码的问题:可读性低 (逻辑散落在大量卫语句中)、违背开闭原则 (新增订单类型需修改现有方法)、测试困难(需构造大量组合条件)。

2. 分步实现:策略模式+工厂方法重构

我们将"计算手续费"抽象为一个策略接口,每种订单类型对应一个实现类,再通过工厂根据订单类型获取策略。

2.1 定义策略接口

复制代码
public interface FeeStrategy {
    double calculate(Order order);
}

2.2 实现具体策略

复制代码
public class NormalFeeStrategy implements FeeStrategy {
    @Override
    public double calculate(Order order) {
        return order.getAmount() < 100 ? 1.0 : 0.5;
    }
}

public class PremiumFeeStrategy implements FeeStrategy {
    @Override
    public double calculate(Order order) {
        UserLevel level = order.getUserLevel();
        if (level == UserLevel.GOLD || level == UserLevel.PLATINUM) {
            return 0.0;
        }
        return 0.3;
    }
}

public class SubscriptionFeeStrategy implements FeeStrategy {
    @Override
    public double calculate(Order order) {
        return 0.2;
    }
}

2.3 创建策略工厂

复制代码
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class FeeStrategyFactory {
    private static final Map<OrderType, FeeStrategy> strategies = new ConcurrentHashMap<>();

    static {
        strategies.put(OrderType.NORMAL, new NormalFeeStrategy());
        strategies.put(OrderType.PREMIUM, new PremiumFeeStrategy());
        strategies.put(OrderType.SUBSCRIPTION, new SubscriptionFeeStrategy());
    }

    public static FeeStrategy getStrategy(OrderType type) {
        FeeStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("Unsupported order type: " + type);
        }
        return strategy;
    }
}

2.4 重构后的计算器

复制代码
public class FeeCalculator {
    public double calculate(Order order) {
        FeeStrategy strategy = FeeStrategyFactory.getStrategy(order.getType());
        return strategy.calculate(order);
    }
}

现在,FeeCalculator.calculate() 只有两行:获取策略 → 执行计算。新增订单类型时,只需添加新的策略实现类并在工厂注册,无需修改现有代码。

3. 验证效果:可读性与可维护性对比

我们来对比重构前后的代码度量:

  • 圈复杂度:重构前方法圈复杂度为 7(多个分支),重构后每个策略类复杂度 ≤ 3,整体平均复杂度从 7 降至 2.5。
  • 单测覆盖率 :重构前需模拟所有组合(3种订单 x 4种用户等级 x 2种金额区间 ≈ 24个case),重构后每个策略独立测试,总case数降至每个策略2~4个,且覆盖度更容易达到100%
  • 可读性 :新代码遵循"单一职责",每个策略类只干一件事,命名即文档。后续维护者看到 NormalFeeStrategy 就能立刻知道其作用。

此外,若后续需要支持动态费率(如从数据库加载配置),只需在工厂中注入配置即可,策略类保持不变。

4. 总结与扩展

本实战展示了如何用策略模式 + 工厂方法 消除卫语句嵌套,核心收益是:降低圈复杂度、提升可测试性、符合开闭原则。对于更复杂的场景(如策略间有依赖或需要组合),可进一步引入责任链模式装饰器模式。建议在团队中推广此类重构,持续改善代码健康度。

相关推荐
龙智DevSecOps解决方案2 天前
Java 重构指南:何时该重构、5 大落地实践以及如何用JRebel/XRebel 加速反馈
jrebel·perforce·java开发·代码重构·xrebel
梁辰兴21 天前
软件工程:程序设计风格
软件工程·代码重构·命名规范·程序设计风格·代码格式·注释规范·良好习惯
AI大模型-小华2 个月前
Codex 长任务频繁中断怎么办?从上下文管理到 ChatGPT Pro 选择
chatgpt·ai编程·软件开发·codex·代码重构·开发效率·chatgpt pro
潘潘的嵌入式日记2 个月前
嵌入式安全重构——新老两套同时跑
嵌入式·架构设计·验证·代码重构
折哥的程序人生 · 物流技术专研3 个月前
Java 23 种设计模式:从踩坑到精通 | 番外:编排器+策略模式在多平台电子面单中的实战(含性能压测)
设计模式·策略模式·代码重构·java设计模式·编排器·电子面单·从踩坑到精通
Python私教3 个月前
用 Claude Code 做大型重构不翻车:分批+Git 兜底+验证闭环的实战流程(2026)
git·重构·ai编程·代码重构·工程实践·claude code
小bo波3 个月前
枚举实战
java·设计模式·枚举·后端开发·代码重构
Thanks_ks5 个月前
软件系统中的熵增定律:技术债的形成与重构的艺术
软件工程·敏捷开发·架构设计·状态管理·代码重构·技术债·康威定律
realhuizhu9 个月前
你的代码正在腐烂:为什么我们都不敢碰那座“屎山”?
ai编程·软件架构·代码重构·deepseek·技术债务