干掉成山的 if-else:工厂造、策略选,一文讲透两个模式的配合

简介: 写给被成堆 if-else 折磨的后端同学:拆开工厂模式和策略模式,搞懂创建与选择的解耦,配合 Spring 实战消灭分支地狱。

大家好,我是晚安code。

你大概率见过这种支付代码:一个 pay() 方法里 if/else 塞了 6 个分支,微信、支付宝、银行卡各占一段,每加一个渠道就再往里堆一块。问起来永远一句「赶进度,先这样吧」。

这种「先这样」最后都会变成「只能这样」。工厂模式和策略模式这俩,一个给「创建对象」解耦,一个给「选择算法」解耦,配合起来正好干掉这种分支地狱。这篇我从生活类比一路讲到 Spring 源码,一次讲透。先收藏,慢慢看。

一、先搞清楚:设计模式到底是什么,为什么要学

设计模式不是炫技,是前人踩坑踩出来的「套路」,让你写出来的代码别人接手时不用骂街。

设计模式(Design Pattern):前人针对反复出现的软件设计问题,总结出的可复用解决方案。你可以把它理解成「代码界的菜谱」——同一道菜(同一个问题),照着成熟配方做,不会翻车。

那为什么非要学?我给你三个最实在的理由:第一是复用,别人趟过的坑你不用再趟一遍;第二是沟通,团队里说一句「这里用工厂模式」,大家都懂你在说什么,省下半小时画图;第三是可维护,符合下面这条原则的代码,加功能不用动老逻辑。

开闭原则(Open-Closed Principle,OCP):软件实体应该「对扩展开放,对修改关闭」——加新功能时尽量加新代码,而不是去改已经在跑的老代码。这条原则是后面两个模式共同的目标。

打个生活化的比方:盖楼不会每栋都从和泥开始,你会用标准化的图纸和预制件;设计模式就是代码世界里的预制件图纸。GoF 23 种模式里,工厂模式和策略模式是出现频率最高的两个,下面我一个个拆给你看。

二、工厂模式:把「new」这件事集中管起来

工厂模式解决的核心痛点是——对象该怎么创建,又不让调用方关心创建细节。

工厂模式(Factory Pattern):把对象的创建过程封装进一个「工厂」角色里,调用方只要告诉工厂「我要什么」,不用自己 new、不用关心构造细节。类比就是去餐厅点餐:你喊一句「来份宫保鸡丁」,后厨怎么切、怎么炒、食材哪来的,你一概不管,上菜就完事。

工厂模式生活类比:餐厅点餐

工厂模式其实分三种,别被名字绕晕,记住区别就行:

  • 简单工厂:一个工厂方法里 switch 一下,返回不同对象。最常用,但严格说不算 GoF 23 种。
  • 工厂方法:每个产品配一个工厂类,加新产品只加新类,完全符合开闭原则。
  • 抽象工厂:管一「族」产品,比如一套前端组件要同时出深色版和浅色版。

放到生活里再秒懂一遍:你点外卖,App 后面是个「订单工厂」,不管它最终走的是哪家配送接口,你只管点;寄件时选顺丰还是圆通,对你来说都是「叫个快递」,背后是不同的快递工厂在创建运单。

开发里这类场景太常见了:根据配置创建不同数据库连接(MySQL / PostgreSQL)、日志组件按需切换(控制台 / 文件 / 远程)、根据消息类型创建不同处理器。核心都是「创建逻辑会变,但调用方不想跟着变」。

看一段最朴素的简单工厂(Java,示例):

// 示例:把支付渠道的创建集中到工厂里
public interface PayChannel {
    void pay(BigDecimal amount); }

public class PayFactory {
   
    public static PayChannel create(String type) {
   
        return switch (type) {
   
            case "wechat" -> new WechatPay();
            case "alipay" -> new AlipayPay();
            default       -> throw new IllegalArgumentException("未知渠道: " + type);
        };
    }
}

// 调用方:不关心怎么 new,只要结果
PayChannel ch = PayFactory.create("alipay");
ch.pay(BigDecimal.valueOf(99));

调用方手里只有 PayChannel 接口,根本不知道 AlipayPay 长啥样。工厂挡在客户端和具体产品中间,客户端只依赖产品接口,加新产品时改工厂、不动调用方:

工厂模式结构示意图:客户端 → 工厂 → 具体产品,客户端只依赖产品接口

到了 Spring,工厂更是遍地都是。BeanFactoryApplicationContext 本身就是个超级大工厂——你调一句 getBean("xxx"),它帮你创建并返回对象,这就是简单工厂的巨型版。FactoryBean 接口更典型:你实现 getObject() 方法自己控制怎么造 Bean,Spring 最终拿到的就是你造出来的对象。集成 MyBatis、Dubbo 时那些代理对象,基本都是靠 FactoryBean 造出来的。

Spring 中的工厂:BeanFactory / FactoryBean

JDK 里也不少:Calendar.getInstance()NumberFormat.getInstance()DriverManager.getConnection(),骨子里都是工厂。

三、策略模式:用「换算法」干掉成山的 if-else

策略模式解决的核心痛点是——同一件事有多种做法,怎么做到想换就换、还不碰老代码。

策略模式(Strategy Pattern):把一组做同一件事的不同算法,各自封装成独立的类,它们实现同一个接口,因此可以互相替换。类比就是导航 App 算路线:「最快」「最省钱」「避开拥堵」就是三个策略,目的地不变,换个策略就走不同的路。

放到生活里再秒懂:去收银台结账,现金、刷卡、扫码是三种「支付策略」,你选哪个都行,但最终都是「完成付款」这一件事。开发里这类场景同样密集:促销打折(满减 / 打折 / 用券)、风控校验(不同等级用户走不同规则)、消息推送(短信 / 邮件 / 站内信)。

先看一段反面教材,这种代码你大概率写过:

// 示例:反面教材——越加越长的折扣方法
public BigDecimal calc(String type, BigDecimal price) {
   
    if ("fullReduction".equals(type)) {
         // 满减
        return price.compareTo(HUNDRED) > 0 ? price.subtract(TEN) : price;
    } else if ("discount".equals(type)) {
       // 打折
        return price.multiply(new BigDecimal("0.8"));
    } else if ("coupon".equals(type)) {
         // 优惠券
        return price.subtract(COUPON);
    }
    return price;
}

每加一种活动,就得改这个方法、加一个分支,几百行挤在一起,老逻辑被反复触碰——典型的违反开闭原则。用策略模式重构一下:

// 示例:策略接口 + 每个算法独立成类
public interface DiscountStrategy {
   
    BigDecimal apply(BigDecimal price);
}

public class DiscountStrategy8 implements DiscountStrategy {
   
    public BigDecimal apply(BigDecimal price) {
    return price.multiply(new BigDecimal("0.8")); }
}

// 调用方持有策略,想换随时换,互不影响
DiscountStrategy s = new DiscountStrategy8();
s.apply(BigDecimal.valueOf(100));

两种写法摆一起对比,差距很明显:

对比项 一坨 if-else 策略模式
加新算法 改老方法、加分支 新增一个策略类,老代码不动
可读性 几百行挤一起 每个算法独立,各管各的
单元测试 分支互相影响,难测 每个策略单独测
开闭原则 不符合 符合

可能有人会问:策略模式不就是把 if-else 换成 map.get() 吗,有啥意义?

形式上像,本质不同。map 只是查找手段;真正的意义是「每个算法独立成类、可单独测试、可热插拔」。更关键的是,它把「选哪个」和「怎么算」拆开了——选哪个交给调用方或工厂,怎么算交给策略自己,职责一清二楚。

JDK 里最经典的策略,是 ThreadPoolExecutor 的拒绝策略 RejectedExecutionHandler:线程池任务满了怎么办?它给你四个策略——AbortPolicy(抛异常)、CallerRunsPolicy(让调用线程自己跑)、DiscardPolicy(直接丢)、DiscardOldestPolicy(丢最老的任务)。换一个 handler,线程池行为完全不同,这就是教科书级的策略模式。

Spring 里也有:Resource 接口,ClassPathResourceFileSystemResourceUrlResource 都是它的实现,访问不同位置的资源用不同策略,Resource 这层抽象把它们统一了起来。

四、为什么它俩总是一起出现:工厂造、策略选

单用策略模式有个尴尬——调用方还得自己 new 具体策略,结果又耦合回去了;工厂模式正好补上这一刀。

你看上面折扣的例子,调用方写的是 new DiscountStrategy8(),它又得知道具体类名,换策略就得改这行 new。这就好比导航 App 让你自己手写每条路线的代码,那还策略个啥。

把工厂请进来就顺了:调用方只说「我要打折策略」,工厂负责把对应的策略对象造出来递过去。策略管「算法怎么算」,工厂管「对象怎么来」,分工一明确,if-else 就彻底没了落脚点。请求带着类型进来,上下文找工厂要策略,工厂从一堆策略里取对的那个,统一调 pay:

工厂 + 策略配合示意图:请求 → 上下文 → 工厂 → 策略集合 → 具体策略

开发里最经典的配合场景就是支付系统:微信、支付宝、银行卡是三个支付策略,再加新渠道(比如 Apple Pay)只是加一个策略类,老代码一行不改。下面是后端最常用的 Spring 写法(以 Spring 6.x、JDK 17 为例,2026 年实测语法):

// 示例:Spring 自动注入 Map,本质就是个策略工厂
public interface PayStrategy {
    void pay(BigDecimal amount); }

@Service("wechat") public class WechatPay implements PayStrategy {
    /* ... */ }
@Service("alipay") public class AlipayPay implements PayStrategy {
    /* ... */ }

@Component
public class PayContext {
   
    @Autowired
    private Map<String, PayStrategy> strategyMap;  // Spring 按 Bean 名自动注入

    public void pay(String type, BigDecimal amount) {
   
        PayStrategy s = strategyMap.get(type);
        if (s == null) throw new IllegalArgumentException("不支持: " + type);
        s.pay(amount);
    }
}

这里的 Map<String, PayStrategy> 就是 Spring 帮你建好的工厂——所有实现了 PayStrategy 的 Bean 自动塞进 Map,key 是 Bean 名。加 Apple Pay?写一个 @Service("applepay") 的类,结束。没有 if-else、没有 switch,完全符合开闭原则。

可能有人会问:这套在非 Spring 项目里还能用吗?

能。没有 Spring,你就自己写个工厂类,在构造方法或静态块里手动 map.put("wechat", new WechatPay()) 注册策略,效果一样。

Spring 只是把「手动注册」这步用依赖注入自动化了,省的是体力,不是思想。

在我看来,工厂模式和策略模式不是两个孤立的面试考点,而是一对搭档:工厂把「创建」关进笼子,策略把「选择」拆成零件,合在一起,你的代码才能做到加功能不动老逻辑。面试官爱问、Spring 源码里遍地都是,恰恰说明它们是真的好用,而不只是八股。下一篇我会聊聊「策略 + 工厂 + 模板方法」三件套,以及怎么用枚举把策略注册也收编掉,感兴趣的话先点个关注。


我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你项目里那些成山的 if-else,最后是怎么被你干掉的?

目录
相关文章
|
7天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2043 11
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
7天前
|
云安全 人工智能 安全
|
7天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
2026年7月,全新旗舰级混合专家大模型Qwen3.8-Max-Preview正式开放抢先体验,作为通义千问Qwen3系列规格最高、综合推理能力顶尖的新一代模型,该模型总参数量达到2.4万亿(2.4T),是当前线上可调用的原生多模态旗舰模型,综合推理水准对标海外顶级Fable 5模型,在复杂工程开发、长文档深度分析、多步骤智能体自治、跨境多语言创作、海量数据挖掘五大高难度业务场景实现跨越式性能提升。
903 1
|
7天前
|
人工智能 自然语言处理 数据挖掘
最新版通义千问(Qwen3.8-Max-Preview)功能介绍
2026年,通义千问正式推出全新旗舰级大模型 **Qwen3.8-Max-Preview 预览版**,作为首款突破万亿参数规格的新一代基座模型,该模型总参数量达到**2.4万亿**,采用全新迭代的MoE混合专家架构,综合推理性能、长文本处理、多模态理解、复杂任务规划能力全面超越前代Qwen3.7-Max版本,整体实力跻身全球第一梯队,可对标海外顶级旗舰模型,是当前面向复杂工程开发、多智能体协同、超长文档解析、专业办公自动化场景的最优国产基座模型。
911 0
|
9天前
|
人工智能
Qwen3.8抢先体验!正式版即将发布并开源!
千问Qwen3.8即将开源,参数达2.4T,进化速度以“天”计,实力媲美Fable 5。预览版Qwen3.8-Max已上线阿里Token Plan等平台,限时优惠:日间Credits低至1折,夜间更优,个人/团队版月付仅35元起!
912 39
|
5天前
|
自然语言处理 测试技术 API
通义千问Qwen3.8-Max-Preview全功能解析:2.4万亿参数旗舰模型深度使用指南
在大模型技术持续迭代的当下,通义千问推出的Qwen3.8-Max-Preview作为新一代旗舰预览版模型,凭借2.4万亿参数的超大规模、多模态融合能力与全场景适配特性,成为开发者与企业用户探索AI应用的核心工具。该模型采用稀疏混合专家(MoE)架构,是通义千问首个突破万亿参数的多模态模型,可同时处理文本、图像、视频与文档等多种数据形态,在全栈代码开发、复杂逻辑推理、长文档分析与多智能体协作等场景实现跨越式升级。本文将全面拆解Qwen3.8-Max-Preview的核心功能,详解API调用流程与配置方法,覆盖多场景实战技巧,帮助用户快速掌握这款旗舰模型的使用方法,充分释放其性能潜力。
444 1
|
8天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max 预览版全解析:2.4 万亿参数旗舰模型,Token Plan 限时优惠指南
Qwen3.8-Max-Preview是通义千问Qwen3系列旗舰MoE大模型,参数达2.4万亿,综合推理能力居行业第一梯队。支持思考/快速双模式,擅长大模型五大高难场景。现于阿里云百炼Token Plan、Qoder及QoderWork上线体验,个人版低至39元/月。在阿里云百炼官网:https://t.aliyun.com/U/fPVHqY 免费领取千万Tokens
669 1
Qwen3.8-Max 预览版全解析:2.4 万亿参数旗舰模型,Token Plan 限时优惠指南