请描述简单工厂模式的工作原理。
- 标签:设计模式
🏛 业务架构师
简单工厂的结构就三步:一个静态工厂方法接收标识(类型参数/字符串),内部 switch 或 Map 路由到具体产品类的构造,返回抽象产品类型。
以支付渠道举例:
PayChannel create(String channelCode) {
switch (channelCode) {
case "ALIPAY": return new AlipayChannel();
case "WECHAT": return new WechatChannel();
default: throw new BizException("渠道不存在");
}
}业务价值在于创建逻辑收口到一处:
- 调用方只依赖 PayChannel 接口,不关心具体类怎么构造(构造可能涉及证书加载、配置读取)——依赖从"具体"提升到"抽象";
- 创建规则变更(新增渠道、渠道初始化参数调整)只改工厂一处,配合 Spring 实际上更常用的是注入
Map<String, PayChannel>按 bean 名路由,连 switch 都省了。
它的局限也要直说:新增产品要改工厂代码,违背开闭原则;产品族多了以后 switch 膨胀。所以我的实践判断:渠道三五个、且新增频率低,简单工厂足够;产品结构会持续膨胀的(营销玩法、计费规则),直接上策略模式 + 注册式工厂(每个实现自注册到容器),为扩展留好口子。
一句话:简单工厂是"把 new 收口"的最小工程化动作,性价比极高;但它是过渡形态,扩展预期明确的业务一开始就该用更开闭的结构,避免半年后推翻重写。
🏗 系统架构师
简单工厂不是 GoF 23 个之一,但它是工厂家族最朴素的形态:一个工厂类 + 一个静态方法,按入参 new 出对应产品。
工作原理:工厂类聚合所有产品的创建逻辑,客户端传类型标识(枚举/字符串),工厂 switch 或 if 返回对应实现。客户端从 new ConcreteProductA() 变成 Factory.create(Type.A),把"造什么"的决策收口到一处。
优缺点(必须辩证讲):
- 优点:创建逻辑集中、客户端与具体类解耦,对象创建复杂(需要读配置、组装依赖)时价值明显;
- 缺点:违背开闭原则——每加一个产品都要改工厂的分支代码,产品多后工厂臃肿成上帝类。
演进路径:分支膨胀后升级为工厂方法(每个产品一个工厂类,加产品加类不改旧代码);产品是"族"(同一维度多个变体组合)时用抽象工厂。配合 Spring 后实践上更优雅:产品类注册成 Bean,工厂注入 Map<String, Product> 按 key 取,零 switch。
我在项目里的用法:支付渠道、通知渠道这类"标识 → 实现"的映射,全部走 Spring Map 注入的简单工厂,新增渠道只需新增实现类,主流程不动。
💻 全栈开发专家
一个工厂类 + 一个静态方法,按入参创建对应的具体产品,把对象的 new 判断收敛到一处。
java
public class PayFactory {
public static PayChannel create(String type) {
switch (type) {
case "alipay": return new AlipayChannel();
case "wechat": return new WechatChannel();
default: throw new IllegalArgumentException("unknown: " + type);
}
}
}
// 调用方
PayChannel channel = PayFactory.create(payType);
channel.pay(order);工作原理三步:调用方传标识 → 工厂内部映射到具体类 → 返回抽象类型(调用方面向接口,不关心具体实现)。
价值:对象创建集中管理,调用方和具体类解耦;新增渠道只改工厂(和新增类)。
缺点(引出工厂方法):违背开闭原则——每加一个产品都要改工厂的分支逻辑。所以简单工厂适合产品种类少且稳定的场景;产品族多、扩展频繁就升级成工厂方法模式(每个产品配一个工厂类,Spring 里 Map<String, PayChannel> 注入其实就是工厂方法的自动化版本,连 switch 都不用写,这是我实际落地的首选)。
面试时能主动说出"简单工厂严格来说不是 GoF 23 种之一"这个细节,也是加分项。