别再写if-else了,我用策略模式重构代码后,同事以为我换人了

2026-04-21 11 0

上周五晚上十点,我接到一个电话。 Caller ID显示是组里的小李,声音里带着一种程序员特有的绝望。

“哥,实在不行了,这个需求能不能不做?”

我问他什么情况。他说组长让他给订单系统加一个新状态——“待拼单”。听起来简单对吧?但是现有的订单状态机已经是一个写了三年的if-else森林,嵌套层级达到五层,他光是理解现有逻辑就花了两天。

我沉默了三秒钟,然后告诉他:“别动,让我来。”

然后我用策略模式重构了整块代码,两小时搞定,留了充足的测试时间,第二天上线无bug。小李看我的眼神,像是在看一个从未来穿越回来的人。

这个故事告诉我们什么?代码的可维护性不是靠注释堆出来的,是靠设计模式打下来的。当然,也告诉我们组长的代码审美需要拯救。

那些if-else森林,最后都怎么样了

我见过最离谱的订单状态逻辑是这样的:

public String processOrder(Order order) {
    if (order != null) {
        if (order.getStatus() == 1) {
            if (order.getAmount() > 100) {
                if (order.getUser().isVip()) {
                    if (order.getCreateTime().after(threshold)) {
                        return "给你打折";
                    } else {
                        return "不给你打折";
                    }
                } else {
                    return "不给你打折";
                }
            } else {
                return "不给你打折";
            }
        } else if (order.getStatus() == 2) {
            // ... 又有三层嵌套
        }
    }
    return "参数错误";
}

看到这段代码的那一刻,我深刻理解了为什么有些程序员相信世界上存在魑魅魍魉。因为这种代码本身就是一个诅咒——你读不懂它,它反过来也会读不懂你。

这种嵌套if-else的代码,业界有一个优雅的名字叫“箭头代码”(Arrow Code),因为缩进看起来像一支箭射向屏幕右边。每次我看到这种代码,都会想起一个笑话:为什么程序员喜欢黑暗?因为亮的地方他们看不清那么多缩进。

策略模式是什么,能不能救人

策略模式(Strategy Pattern)大概是Gang of Four里最实用的一员,其他几位兄长——工厂、抽象工厂、单例——在实战中要么被过度使用,要么被误解使用,只有策略模式是我每次重构新项目时第一个想到的工具哥。

策略模式的核心思想很简单:把算法/行为封装成独立对象,使用时不需要知道它的具体实现。这听起来简单到像废话,但我见过太多程序员宁愿写一百行if-else也不愿意写一个接口。

具体怎么用?我拿小李的订单状态问题来做演示。

第一步,定义订单状态处理接口:

public interface OrderStatusHandler {
    /**
     * 处理订单
     * @param order 订单实体
     * @return 处理结果
     */
    OrderResult handle(Order order);
    
    /**
     * 获取该处理器支持的状态
     */
    OrderStatus getSupportedStatus();
}

第二步,为每个状态写一个具体策略:

@Component
public class Pending拼单Handler implements OrderStatusHandler {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private 拼单Service 拼单Service;
    
    @Override
    public OrderStatus getSupportedStatus() {
        return OrderStatus.PENDING拼单;
    }
    
    @Override
    public OrderResult handle(Order order) {
        // 这里是纯业务逻辑,没有任何if-else
        // 如果需要拼单,发起拼单
        // 如果拼单超时,走超时逻辑
        // 如果用户主动取消,取消拼单
        return orderService.发起拼单(order);
    }
}

第三步,也是最关键的一步——用一个工厂或者Map来管理这些策略:

@Component
public class OrderStatusHandlerFactory {
    
    private final Map<OrderStatus, OrderStatusHandler> handlerMap;
    
    @Autowired
    public OrderStatusHandlerFactory(List<OrderStatusHandler> handlers) {
        this.handlerMap = handlers.stream()
            .collect(Collectors.toMap(
                OrderStatusHandler::getSupportedStatus,
                Function.identity(),
                (existing, replacement) -> replacement
            ));
    }
    
    public OrderResult process(Order order) {
        OrderStatusHandler handler = handlerMap.get(order.getStatus());
        if (handler == null) {
            throw new IllegalStateException("未找到状态处理器: " + order.getStatus());
        }
        return handler.handle(order);
    }
}

现在,新增一个状态需要做什么?只需要写一个新的Handler实现类,然后在类上加一个@Component注解。Spring会自动发现它,自动注册进工厂。你甚至不需要修改任何现有代码——开闭原则(Open-Closed Principle)在这里被天然满足。

为什么你的同事不愿意改设计模式

这里我要说一些得罪人的话。拒绝设计模式的人,大多数不是不懂设计模式,而是懒得动脑子。他们觉得写if-else够用,反正能跑,反正确认测试过了。

但这里有个经典的工程师认知偏差:把“能跑”等同于“好代码”。 代码能跑和代码写得好是两码事,就像一个人能走路和一个人走得优雅不是一回事。

更可怕的是,if-else森林最阴险的地方在于它的积累效应。每一行if-else看起来都合理,几个嵌套看起来也还能接受。但是当系统运行两三年,加了十几个状态,每个状态又各有三五种分支的时候,这个代码就成了谁都不敢动的结界。

这时候你跟新人说“来,给订单加个‘已退款’状态”,新人的表情大概是这样的:😱

策略模式的几个实战要点

不是所有场景都适合策略模式。我在这里说几个判断标准:

适合的场景:

  • 多个地方有类似逻辑但具体细节不同(状态处理、支付渠道、通知方式)
  • 需要动态切换算法/行为
  • 新增逻辑是常态而不是例外(业务规则频繁变更)

不太适合的场景:

  • 逻辑极其简单,最多两个分支,不会再扩展
  • 性能敏感到不能接受接口调用开销(但说真的,大多数场景下这不是问题)

另外有一个实战经验:如果一个方法里的if-else超过三层,或者整个方法的代码量超过了80行,你就要警惕了。这不是严谨的衡量标准,但是一个经验值——当代码复杂度达到这个阈值时,维护成本已经开始超过设计成本了。

最后说点真心话

我知道写这篇文章可能会被一些老手吐槽:“设计模式又不是万能药”“过度工程化也是坑”。这些我都同意。设计模式不是银弹,但if-else也不是。

我见过太多项目死于两种极端:一种是从来不重构,if-else堆到天荒地老;另一种是拿到产品需求就开始画类图,恨不得把所有模式都用上,结果一个简单的CRUD写了二十个类。

好的工程判断力在于知道什么时候该用设计模式,什么时候不该用。这不是从书里学来的,是从踩坑里爬出来的。

但有一点我可以打包票:当你面对的是一个复杂的业务状态机,面对的是一个不断加新状态新规则的系统,别犹豫,上策略模式。三个月后你会回来感谢我。六个月后当你轻松加一个新状态而不用在旧代码里穿梭跳跃时,你会想起那个建议你用策略模式的晚上。

那时候给我点个赞就行。

(本文作者是一个被箭头代码伤害过的人,如果你正在经历类似的情况,请考虑给你的代码买一份策略模式保险。)

相关文章

🤖 AI探索|最近我在信息洪流里捞到的好东西
还在为部署AI工具抓狂?让小龙虾帮你搞定!🦞
API写得好不好,看这10条就知道——别让你的接口成为团队噩梦
服务器快炸了?恭喜你,终于发现了资源泄漏这个老朋友 🦞
我写API被喷了三年,才明白这些坑不能踩
当AI开始抢我饭碗时,我的内心OS是这样的

发布评论