简单工厂将对象创建逻辑集中到工厂类中,使业务代码只依赖接口而不关心具体实现,从而实现解耦;新增支付方式只需修改工厂类,无需改动业务代码。

为什么简单工厂里不能直接 new 具体类
因为一旦在业务代码里写 new PaymentWechat() 或 new PaymentAlipay(),创建逻辑就和使用逻辑绑死了。后续加新支付方式、换实现、做 mock 测试,都得改业务代码——这不是解耦,是焊死。
简单工厂的核心动作,就是把 new 这个操作收拢到一个单独的类(比如 PaymentFactory)里,用多态向上转型,让调用方只依赖 Payment 接口,不关心背后是谁。
- 工厂方法返回类型必须是接口或父类,比如
Payment create(String type) - 所有具体实现类(
PaymentWechat、PaymentAlipay)都要实现该接口 - 工厂内部用
if-else或switch判断类型,但外部完全看不到这些分支
如何让工厂支持新增类型而不改原有代码
严格来说,标准简单工厂做不到“完全不改”——它的 create() 方法里必然有判断逻辑。但可以控制修改范围:只动工厂类,不动业务类、不改接口、不碰已有实现类。
常见错误是把类型字符串硬编码在业务侧:factory.create("wechat"),结果哪天拼错成 "weichat",运行时报 NullPointerException 都不知道哪来的。更稳妥的是用枚举限定合法类型。
立即学习“Java免费学习笔记(深入)”;
- 定义
enum PaymentType { WECHAT, ALIPAY, UNIONPAY } - 工厂方法签名改为
Payment create(PaymentType type),避免字符串误传 - 新增类型时,只需扩展枚举 + 在工厂
switch中加一个case+ 写新实现类 - 不要在工厂里用
Class.forName().newInstance()——反射绕过编译检查,出错晚、难调试
多态在这里到底起了什么作用
不是为了炫技,而是让“调用方不感知实现变化”。业务代码拿到的是 Payment 类型的引用,调用 pay() 时,JVM 根据实际对象类型自动分派到对应实现——这个动态绑定过程,就是多态在扛事。
如果工厂返回的是具体类型(比如 PaymentWechat),那业务代码变量声明也得跟着变,一加新支付方式就得批量改声明、改调用,彻底失去弹性。
- 接口定义行为契约:
void pay(BigDecimal amount) - 每个实现类覆盖自己的逻辑,但签名不变
- 工厂返回
Payment,业务代码只调payment.pay(...),连instanceof都不该出现 - 测试时可直接传入 mock 实现,无需启动真实支付通道
简单工厂和策略模式容易混淆的边界
它们长得像,但目的不同:简单工厂专注“怎么造出来”,策略模式专注“造出来后怎么用”。你可能在一个项目里同时用两者——工厂负责生成策略实例,策略接口本身由多态驱动。
典型踩坑是把工厂类写成策略上下文:比如在 PaymentContext 里既缓存实例又做类型路由。这会让职责混乱,一旦要支持同一类型多个配置(如两个不同的微信商户号),就卡住。
- 工厂只做一件事:根据输入,返回一个符合接口的新对象
- 策略上下文(如
PaymentExecutor)负责持有、执行、切换策略,不参与创建 - 如果创建逻辑变复杂(比如需依赖配置中心、需初始化连接池),简单工厂应升级为工厂方法或抽象工厂,而不是硬塞更多 if
多态是基础,但别指望靠它掩盖设计失衡。工厂类开始出现“创建前校验参数”“创建后设置回调”“缓存单例实例”这些逻辑时,就该停下来想想:它是不是已经不只是“简单”工厂了。









