摘要:你是不是也遇到过这种情况?接手老项目时,打开文件就看到层层嵌套的 if/else,像一团乱麻;新增需求时,只能在原有分支里 “挤牙膏” 式加代码,生怕一动就触发隐藏 BUG;甚至上线后,因为某个分支判断漏写,半夜被运维电话叫醒改 BUG—— 这种被 “条件分支
你是不是也遇到过这种情况?接手老项目时,打开文件就看到层层嵌套的 if/else,像一团乱麻;新增需求时,只能在原有分支里 “挤牙膏” 式加代码,生怕一动就触发隐藏 BUG;甚至上线后,因为某个分支判断漏写,半夜被运维电话叫醒改 BUG—— 这种被 “条件分支绑架” 的日子,真的该结束了!
今天咱们不聊虚的,直接用 “代码对比 + 实战案例” 告诉你:搞定冗余条件分支,核心就靠 “合理抽象 + 设计模式”,看完这篇,你也能写出让同事忍不住点赞的简洁代码。
咱们先拿开发中最常见的 “支付回调处理” 场景举例,看看冗余分支和优化代码的差距到底有多大。
// 处理支付回调:根据支付方式(微信/支付宝/银联)执行不同逻辑public void handlePaymentCallback(String payType, String callbackData) { if ("WECHAT".equals(payType)) { // 微信支付回调处理:验签、解析数据、更新订单状态 WechatPayUtil.verifySign(callbackData); WechatCallbackDTO wechatDTO = JsonUtil.parse(callbackData, WechatCallbackDTO.class); orderService.updateStatus(wechatDTO.getOrderId, "PAID"); log.info("微信支付回调处理完成,订单号:{}", wechatDTO.getOrderId); } else if ("ALIPAY".equals(payType)) { // 支付宝支付回调处理:验签规则不同、数据格式不同 AlipayUtil.verifySign(callbackData); AlipayCallbackDTO alipayDTO = JsonUtil.parse(callbackData, AlipayCallbackDTO.class); orderService.updateStatus(alipayDTO.getOutTradeNo, "PAID"); log.info("支付宝支付回调处理完成,订单号:{}", alipayDTO.getOutTradeNo); } else if ("UNIONPAY".equals(payType)) { // 银联支付回调处理:还有额外的通知日志记录 UnionPayUtil.verifySign(callbackData); UnionPayCallbackDTO unionPayDTO = JsonUtil.parse(callbackData, UnionPayCallbackDTO.class); orderService.updateStatus(unionPayDTO.getOrderNumber, "PAID"); notifyLogService.record(unionPayDTO.getOrderNumber, "银联支付成功"); log.info("银联支付回调处理完成,订单号:{}", unionPayDTO.getOrderNumber); } else { throw new IllegalArgumentException("不支持的支付方式:" + payType); }}这段代码你眼熟吗?每次加新支付方式(比如京东支付、ApplePay),都要在 if/else 里加新分支,代码越堆越长,而且验签、解析、更新状态的逻辑混在一起,想单独改某个支付方式的逻辑,都怕影响其他分支。
先定义一个支付回调处理器接口,把共性逻辑抽象出来:
// 支付回调处理器接口:定义统一方法public interface PaymentCallbackHandler { // 支持的支付方式(如WECHAT/ALIPAY) String supportPayType; // 处理回调逻辑 void handle(String callbackData);}再为每种支付方式写具体实现类,职责单一:
// 微信支付处理器@Componentpublic class WechatPaymentHandler implements PaymentCallbackHandler { @Override public String supportPayType { return "WECHAT"; } @Override public void handle(String callbackData) { WechatPayUtil.verifySign(callbackData); WechatCallbackDTO dto = JsonUtil.parse(callbackData, WechatCallbackDTO.class); orderService.updateStatus(dto.getOrderId, "PAID"); log.info("微信支付回调处理完成,订单号:{}", dto.getOrderId); }}// 支付宝支付处理器(同理,银联、京东支付也各写一个)@Componentpublic class AlipayPaymentHandler implements PaymentCallbackHandler { // 实现逻辑省略,只关注支付宝特有的处理}最后用 “工厂模式” 获取处理器,消除所有 if/else:
// 支付回调工厂:根据支付方式获取对应的处理器@Componentpublic class PaymentCallbackHandlerFactory { // 自动注入所有PaymentCallbackHandler实现类 private final MaphandlerMap; // 构造函数:将处理器按“支付方式”存入map public PaymentCallbackHandlerFactory(Listhandlers) { this.handlerMap = handlers.stream .collect(Collectors.toMap(PaymentCallbackHandler::supportPayType, h -> h)); } // 获取处理器 public PaymentCallbackHandler getHandler(String payType) { PaymentCallbackHandler handler = handlerMap.get(payType); if (handler == null) { throw new IllegalArgumentException("不支持的支付方式:" + payType); } return handler; }}// 最终调用:一行代码搞定,加新支付方式只需加新处理器public void handlePaymentCallback(String payType, String callbackData) { PaymentCallbackHandler handler = factory.getHandler(payType); handler.handle(callbackData);}
对比下来是不是很明显?优化后的代码没有一个 if/else,新增支付方式时不用改原有逻辑,直接加个处理器类就行,后期维护也能精准定位到具体实现 —— 这就是 “合理抽象 + 设计模式” 的威力。
看完代码对比,你可能会问:“不同场景下,优化方法是不是都不一样?” 其实不是,不管是支付回调、消息推送,还是业务状态流转,搞定冗余条件分支的核心就 2 个:
冗余分支的根源,往往是把 “变化的逻辑” 和 “固定的流程” 混在了一起。比如上面的支付回调,“验签、解析、更新状态” 是每个支付方式都要做的(不变的流程),但 “怎么验签、解析什么格式” 是变化的(不同支付方式不同)。
所以第一步要做的,就是把 “变化的逻辑” 抽成独立的模块(比如接口 + 实现类),“不变的流程” 留在主逻辑里 —— 这样主逻辑不用动,变化的部分单独维护。
很多开发者觉得设计模式 “太复杂、用不上”,但其实针对条件分支,有 3 个模式几乎能覆盖 80% 的场景,而且实现起来很简单:
策略模式:像支付回调这样,“不同类型对应不同处理逻辑”,用策略模式(接口 + 多实现)+ 工厂模式,直接消除 if/else;状态模式:如果是 “根据业务状态执行不同操作”(比如订单从 “待支付” 到 “已支付” 再到 “已发货”),用状态模式把每个状态的行为封装起来,避免状态判断的分支;责任链模式:如果是 “多个条件按顺序判断,满足一个就执行”(比如接口权限校验:先验 token,再验角色,最后验资源权限),用责任链把每个校验步骤串起来,不用写多层 if。这 3 个模式不用死记,记住 “场景匹配” 就行:类型判断用策略,状态流转用状态,顺序校验用责任链。
光说理论不够,咱们再拿 2 个高频场景举例,看看不同场景下怎么落地优化,代码你可以直接复制到项目里改改就用。
需求:根据用户设置的推送方式(短信 / 微信模板消息 / APP 推送),发送不同类型的通知(订单通知 / 活动通知)。
优化前:一堆 if/else 判断推送方式,每个方式的发送逻辑混在一起:
public void sendNotification(String pushType, String notifyType, String userId, String content) { if ("SMS".equals(pushType)) { if ("ORDER".equals(notifyType)) { SmsUtil.sendOrderSms(userId, content); } else if ("ACTIVITY".equals(notifyType)) { SmsUtil.sendActivitySms(userId, content); } } else if ("WECHAT".equals(pushType)) { if ("ORDER".equals(notifyType)) { WechatMsgUtil.sendOrderTemplateMsg(userId, content); } else if ("ACTIVITY".equals(notifyType)) { WechatMsgUtil.sendActivityTemplateMsg(userId, content); } } // 后续加APP推送,还要再加一层else if}// 1. 定义推送处理器接口public interface NotificationHandler { // 支持的(推送方式+通知类型),比如"SMS_ORDER" String supportType; void send(String userId, String content);}// 2. 实现具体处理器,比如短信订单通知@Componentpublic class SmsOrderNotificationHandler implements NotificationHandler { @Override public String supportType { return "SMS_ORDER"; } @Override public void send(String userId, String content) { SmsUtil.sendOrderSms(userId, content); }}// 3. 工厂类:根据组合类型获取处理器@Componentpublic class NotificationHandlerFactory { private final MaphandlerMap; public NotificationHandlerFactory(Listhandlers) { this.handlerMap = handlers.stream .collect(Collectors.toMap(NotificationHandler::supportType, h -> h)); } public NotificationHandler getHandler(String pushType, String notifyType) { String key = pushType + "_" + notifyType; NotificationHandler handler = handlerMap.get(key); if (handler == null) { throw new IllegalArgumentException("不支持的推送组合:" + key); } return handler; }}// 4. 最终调用:一行代码,加新组合只需加新处理器public void sendNotification(String pushType, String notifyType, String userId, String content) { NotificationHandler handler = factory.getHandler(pushType, notifyType); handler.send(userId, content);}需求:订单状态从 “待支付”(PENDING)到 “已支付”(PAID)、“已取消”(CANCELLED),再到 “已发货”(SHIPPED),每个状态下能执行的操作不同(比如待支付状态只能支付或取消,已支付状态只能发货)。
优化前:用 if/else 判断当前状态,再判断能执行的操作,逻辑混乱:
public void updateOrderStatus(String orderId, String currentStatus, String targetStatus) { Order order = orderService.getById(orderId); if ("PENDING".equals(currentStatus)) { if ("PAID".equals(targetStatus)) { order.setStatus("PAID"); // 触发支付成功后续操作:扣库存、发通知 inventoryService.deduct(order.getProductId, order.getQuantity); notificationService.sendOrderPaidMsg(order.getUserId, orderId); } else if ("CANCELLED".equals(targetStatus)) { order.setStatus("CANCELLED"); // 触发取消后续操作:释放库存 inventoryService.release(order.getProductId, order.getQuantity); } else { throw new IllegalArgumentException("待支付订单不能转为:" + targetStatus); } } else if ("PAID".equals(currentStatus)) { if ("SHIPPED".equals(targetStatus)) { order.setStatus("SHIPPED"); notificationService.sendOrderShippedMsg(order.getUserId, orderId); } else { throw new IllegalArgumentException("已支付订单不能转为:" + targetStatus); } } orderService.updateById(order);}优化后:用状态模式把每个状态的行为封装,主逻辑不用判断状态:
// 1. 定义订单状态接口:每个状态能执行的操作public interface OrderState { // 支付操作 void pay(Order order); // 取消操作 void cancel(Order order); // 发货操作 void ship(Order order);}// 2. 实现待支付状态:只能pay或cancel,不能shippublic class PendingOrderState implements OrderState { @Override public void pay(Order order) { // 支付逻辑:改状态、扣库存、发通知 order.setStatus("PAID"); inventoryService.deduct(order.getProductId, order.getQuantity); notificationService.sendOrderPaidMsg(order.getUserId, order.getId); } @Override public void cancel(Order order) { // 取消逻辑:改状态、释放库存 order.setStatus("CANCELLED"); inventoryService.release(order.getProductId, order.getQuantity); } @Override public void ship(Order order) { // 待支付订单不能发货,直接抛异常 throw new IllegalStateException("待支付订单不能执行发货操作"); }}// 3. 实现已支付状态:只能ship,不能pay或cancel(同理)public class PaidOrderState implements OrderState { @Override public void pay(Order order) { throw new IllegalStateException("已支付订单不能重复支付"); } @Override public void cancel(Order order) { throw new IllegalStateException("已支付订单需先退款才能取消"); } @Override public void ship(Order order) { order.setStatus("SHIPPED"); notificationService.sendOrderShippedMsg(order.getUserId, order.getId); }}// 4. 订单类:持有当前状态,委托状态执行操作public class Order { private String id; private String status; private OrderState currentState; // 构造时根据初始状态设置currentState public Order(String status) { this.status = status; this.currentState = getStateByStatus(status); } // 根据状态字符串获取状态对象 private OrderState getStateByStatus(String status) { if ("PENDING".equals(status)) { return new PendingOrderState; } else if ("PAID".equals(status)) { return new PaidOrderState; } throw new IllegalArgumentException("不支持的订单状态:" + status); } // 对外提供的操作方法:委托给currentState public void pay { currentState.pay(this); // 操作后更新状态字符串 this.status = "PAID"; } public void cancel { currentState.cancel(this); this.status = "CANCELLED"; } public void ship { currentState.ship(this); this.status = "SHIPPED"; } // getter/setter省略}// 5. 最终调用:直接调用订单对象的方法,不用管状态判断public void updateOrderStatus(String orderId, String operation) { Order order = orderService.getById(orderId); switch (operation) { case "PAY": order.pay; break; case "CANCEL": order.cancel; break; case "SHIP": order.ship; break; } orderService.updateById(order);}这样一来,新增订单状态(比如 “已完成”)时,只需加一个CompletedOrderState类,不用改原有状态的逻辑,彻底解决 “状态判断分支” 的问题。
最后,给你一个小习惯:写代码前如果发现要写 if/else,先问自己 3 个问题,能帮你提前避开冗余分支的坑:
这些分支是不是 “不同类型 / 状态的处理逻辑”? 如果是,先想能不能用策略模式或状态模式抽象,而不是直接堆分支;未来会不会加新的分支? 如果大概率会(比如支付方式、通知类型),一定要做抽象,不然后期改代码会很痛苦;这段逻辑能不能拆成 “小而单一” 的模块? 比如每个分支的处理逻辑超过 10 行,就该拆成独立方法或类,避免一个方法里堆满分支。其实,优雅的代码不是 “写出来的”,而是 “设计出来的”。少写一行 if/else,后期就少一分维护成本
来源:光明教育