1.1 工厂模式
工厂模式(Factory)回答一个看似简单、实则反复出现的问题:该由谁来决定 new 哪个具体类?
当你在代码里写下 new EmailNotifier() 时,调用方就和这个具体类“焊死”了。一旦需要支持短信、推送、Slack,调用方就要塞进越来越多的 if/else,而且这种判断会复制粘贴到每一个使用通知的地方。工厂模式把“创建哪个对象”的决定从调用方手里收走,集中到一个地方。
注意
核心压力:调用方需要一个对象,但不应该关心这个对象的具体类型是怎么选出来的。让调用方只依赖抽象接口,把“选择具体实现”的脏活交给工厂。
下面这个工厂下单台演示了这一点:你只告诉工厂“要哪种通知”,工厂负责挑选并创建正确的具体类,而那行客户端调用代码 factory.create(channel).send(msg) 始终不变。
正在加载交互实验...
简单工厂、工厂方法与抽象工厂
“工厂”其实是一族说法,先把名字理清:
- 简单工厂(Simple Factory):一个方法里用
switch/if根据参数返回不同子类。它不是 GoF 正式模式,但最常用、最易懂。
- 工厂方法(Factory Method):把“创建”这一步定义成抽象方法,由子类决定实例化哪个类。它用继承来扩展产品。
- 抽象工厂(Abstract Factory):创建“一整族”相关产品,下一节专门讲。
本节聚焦最实用的简单工厂与工厂方法。一段典型的工厂方法骨架:
java
interface Notifier {
void send(String message);
}
class NotifierFactory {
Notifier create(String channel) {
switch (channel) {
case "email": return new EmailNotifier();
case "sms": return new SmsNotifier();
case "push": return new PushNotifier();
default: throw new IllegalArgumentException(channel);
}
}
}调用方只看见 Notifier 接口;新增一种渠道,只需要加一个实现类,并在工厂里加一行。
正在加载概念检查...
为什么这是开闭原则的胜利
把创建逻辑散落在各处时,新增一种产品类型意味着你要找出每一处 new、每一处 if,逐个修改。漏掉一处就是一个 bug。
把创建集中到工厂后,新增类型只改工厂这一处,其他调用点纹丝不动——这正是开闭原则(对扩展开放、对修改关闭)想要的效果。下面的对照器让你亲眼看到“受影响的代码点”数量如何随着是否使用工厂而变化。
正在加载交互实验...
什么时候不要用工厂
模式是有成本的。如果:
- 你只有一个具体实现,而且短期内不会有第二个;
- 创建逻辑就是一句
new,没有参数选择、没有分支;
那么直接 new 反而最清晰。过早引入工厂只会增加一层无谓的间接,让读代码的人多跳一次。先有重复的创建压力,再引入工厂。
注意
常见误用:不要把工厂变成“万能上帝类”,在一个
create() 里塞进几十种风马牛不相及的产品。当分支太多时,考虑用注册表(map 从 key 到 supplier)或多态来拆分。正在加载概念检查...
下面的练习让你把一段“到处 new”的通知代码,重构成依赖工厂与接口的版本。
正在加载本节练习...