工厂模式是一种创建型设计模式,它的核心思想是:
将对象的创建过程抽象出来,使用工厂类(方法)代替直接使用 new。
通俗理解:把“用 new 创建对象”的逻辑交给“工厂”处理,让调用者无需关心具体实现细节。
在面向对象编程中,我们往往使用 new 关键字直接实例化对象。然而,随着系统复杂度提升,直接使用 new 会带来以下一系列问题:
直接使用 new 会让调用者依赖于具体实现类,导致模块之间耦合紧密。一旦对象的创建方式改变(如构造参数、初始化流程),调用者也必须改动代码。
举例:
// 调用方直接创建对象
MessageSender sender = new EmailSender("smtp.xx.com");
一旦你决定切换为 SmsSender 或加入池化逻辑,调用方必须同步更改,违背“对修改关闭”的开闭原则。
使用工厂:
MessageSender sender = SenderFactory.create("email");
创建逻辑完全封装,调用方只依赖接口,降低耦合。
在某些场景下,对象构建可能涉及大量参数配置、外部依赖注入、对象池复用、缓存判断等操作。将这些复杂逻辑交由工厂集中管理,有助于保持业务代码简洁清晰。
举例:
你在构建一个 DatabaseConnection,创建过程如下:
DatabaseConnection conn = new DatabaseConnection(
getDriver(), getUrl(), getUsername(), getPassword(), loadPool()
);
这种初始化逻辑若在多处重复调用,代码难以维护,甚至引发参数不一致等 Bug。
工厂改造后:
DatabaseConnection conn = ConnectionFactory.createConnection();
不仅调用简洁,且参数设置、依赖注入、对象池可统一管理。
当系统需要引入更多“产品”时,直接 new 的方式必须修改原有逻辑,而工厂模式允许你通过新增类实现扩展,无需改动原有代码。
举例:
你开发了一个 LogWriter 系统,初始只支持写文件日志:
LogWriter writer = new FileLogWriter();
后续产品需求:增加 KafkaLogWriter、DatabaseLogWriter,此时:
•若直接 new,需大量 if/else
•若使用工厂方法模式,只需新增对应实现和工厂类
这样便可以实现“对扩展开放、对修改关闭”。
使用工厂模式可以让你通过接口或抽象类构建对象,从而在测试中轻松替换为 mock 实现,提高测试灵活性。
举例:
// 正常使用
MessageSender sender = SenderFactory.create("email");
// 测试中替换为 mock
MessageSender sender = new MockSender();
若你将对象硬编码在业务中 new EmailSender(),则测试中难以注入 Mock 对象。
工厂模式支持根据配置或上下文动态创建对象,是实现插件式架构、策略模式的关键支撑机制之一。
举例:
// 从配置文件中读取 sender 类型
String senderType = config.get("message.sender"); // "sms", "email", "wechat"
MessageSender sender = SenderFactory.create(senderType);
这类工厂配合 Spring、Guice 等 IOC 容器,可实现全系统模块解耦、热插拔、模块化开发。
原因 |
描述 |
---|---|
解耦创建与使用 |
避免调用方依赖具体类,提高模块独立性 |
隐藏复杂逻辑 |
封装对象构造的复杂性,简化业务逻辑 |
便于扩展 |
增加新产品无需修改已有代码,符合开闭原则 |
增强测试性与可替代性 |
接口编程易于 Mock 测试,提高可维护性 |
支持灵活配置 / 插件式架构 |
动态构建对象、支持配置驱动,适合策略模式、IOC 场景 |
你去星巴克点咖啡:
•你不需要知道咖啡是怎么煮出来的
•你只说:“我要一杯拿铁”
•店员(工厂)会帮你准备好对应的饮品
你只关心产品的“类型”,而不关心具体的构建细节,这就是“工厂模式”。
•日志系统(返回不同日志记录器)
•数据库驱动(返回 MySQL、PostgreSQL 等连接对象)
•UI 框架(根据配置创建按钮、下拉框等组件)
•消息中间件封装(KafkaProducerFactory)
核心思想:由一个工厂类根据参数返回不同子类对象
interface Product {
void use();
}
class ProductA implements Product {
public void use() { System.out.println("Using ProductA"); }
}
class ProductB implements Product {
public void use() { System.out.println("Using ProductB"); }
}
class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) return new ProductA();
if ("B".equals(type)) return new ProductB();
throw new IllegalArgumentException("Unknown type: " + type);
}
}
使用方式:
Product p = SimpleFactory.createProduct("A");
p.use(); // 输出:Using ProductA
❌ 缺点:添加新产品时需要修改工厂代码,违背开闭原则
问题场景:
你为某个物联网项目写了一个 DeviceFactory.create("Sensor"),但后续硬件种类越来越多,每新增一个设备就得修改原有工厂类,最终变成了数百行的 if-else。
这会导致代码膨胀、难以维护。
核心思想:每种产品由自己的工厂类负责创建,工厂变得可扩展
interface Product {
void use();
}
class ProductA implements Product {
public void use() { System.out.println("Using ProductA"); }
}
interface ProductFactory {
Product createProduct();
}
class ProductAFactory implements ProductFactory {
public Product createProduct() {
return new ProductA();
}
}
使用方式:
ProductFactory factory = new ProductAFactory();
Product product = factory.createProduct();
product.use(); // 输出:Using ProductA
✅ 优点:符合开闭原则,扩展新产品无需改动原有工厂代码
❌ 缺点:每增加一种产品,都要新增一个工厂类,类数量变多
问题场景:
你在写一个图形渲染引擎,每种图形(Circle、Square、Triangle)都用一个 Factory 实现,结果光工厂类就有 20 个,新人很难理清结构。
核心思想:为一组相关或相互依赖的产品提供一个统一的创建接口
适合于一整套产品族创建,如 GUI 工具包中 Mac 风格 和 Windows 风格 UI。
interface Button {
void click();
}
interface TextField {
void input();
}
interface GUIFactory {
Button createButton();
TextField createTextField();
}
// Mac 风格实现
class MacButton implements Button {
public void click() { System.out.println("MacButton Clicked"); }
}
class MacTextField implements TextField {
public void input() { System.out.println("MacTextField Input"); }
}
class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public TextField createTextField() { return new MacTextField(); }
}
使用方式:
GUIFactory factory = new MacFactory();
Button button = factory.createButton();
button.click(); // MacButton Clicked
✅ 优点:创建一族产品时保证一致性(外观统一)
❌ 缺点:产品族增加容易,产品种类增加麻烦
问题场景:
你开发一个跨平台桌面应用(支持 Windows / Mac / Linux),使用抽象工厂创建不同风格控件,但 UI 突然要求“新增滑动条组件”,结果每个产品族都要实现一套 Slider 系列,实现成本大幅上升。
模式 |
是否支持扩展产品 |
是否支持扩展产品族 |
使用场景 |
---|---|---|---|
简单工厂 |
❌(需修改工厂类) |
❌ |
产品少,变化不大 |
工厂方法 |
✅(新增工厂类) |
❌ |
产品频繁扩展 |
抽象工厂 |
✅ |
✅ |
产品有多个系列、界面一致性要求 |
不希望外部依赖 new 创建对象
对象创建复杂,需要预处理、配置等
系统产品种类频繁变更、需解耦模块间依赖
想通过接口编程,利于单元测试、模拟
工厂模式本质是解耦对象创建与使用
三种实现各有优缺点,应按项目复杂度、扩展性选择
不要滥用,过度抽象会带来维护负担
下一篇将带你深入讲解「建造者模式」的核心思想与进阶用法
如需Java面试题资料,可关注公众号:小健学Java,回复“面试”即可获得!