深入设计模式之「工厂模式」:什么是工厂模式?该如何使用?

一、什么是工厂模式(Factory Pattern)?

工厂模式是一种创建型设计模式,它的核心思想是:

将对象的创建过程抽象出来,使用工厂类(方法)代替直接使用 new。

通俗理解:把“用 new 创建对象”的逻辑交给“工厂”处理,让调用者无需关心具体实现细节。


二、为什么要使用工厂模式?

在面向对象编程中,我们往往使用 new 关键字直接实例化对象。然而,随着系统复杂度提升,直接使用 new 会带来以下一系列问题:

1. 解耦对象的创建与使用,提高模块独立性

直接使用 new 会让调用者依赖于具体实现类,导致模块之间耦合紧密。一旦对象的创建方式改变(如构造参数、初始化流程),调用者也必须改动代码。

举例:

// 调用方直接创建对象
MessageSender sender = new EmailSender("smtp.xx.com");

一旦你决定切换为 SmsSender 或加入池化逻辑,调用方必须同步更改,违背“对修改关闭”的开闭原则

使用工厂:

MessageSender sender = SenderFactory.create("email");

创建逻辑完全封装,调用方只依赖接口,降低耦合。


2. 隐藏复杂的创建逻辑,封装变化

在某些场景下,对象构建可能涉及大量参数配置、外部依赖注入、对象池复用、缓存判断等操作。将这些复杂逻辑交由工厂集中管理,有助于保持业务代码简洁清晰

举例:

你在构建一个 DatabaseConnection,创建过程如下:

DatabaseConnection conn = new DatabaseConnection(
    getDriver(), getUrl(), getUsername(), getPassword(), loadPool()
);

这种初始化逻辑若在多处重复调用,代码难以维护,甚至引发参数不一致等 Bug。

工厂改造后:

DatabaseConnection conn = ConnectionFactory.createConnection();

不仅调用简洁,且参数设置、依赖注入、对象池可统一管理。


3. 提升系统可扩展性(符合开闭原则)

当系统需要引入更多“产品”时,直接 new 的方式必须修改原有逻辑,而工厂模式允许你通过新增类实现扩展,无需改动原有代码

举例:

你开发了一个 LogWriter 系统,初始只支持写文件日志:

LogWriter writer = new FileLogWriter();

后续产品需求:增加 KafkaLogWriter、DatabaseLogWriter,此时:

•若直接 new,需大量 if/else

•若使用工厂方法模式,只需新增对应实现和工厂类

这样便可以实现“对扩展开放、对修改关闭”。


 4. 提升测试性与可维护性

使用工厂模式可以让你通过接口或抽象类构建对象,从而在测试中轻松替换为 mock 实现,提高测试灵活性。

举例:

// 正常使用
MessageSender sender = SenderFactory.create("email");
// 测试中替换为 mock
MessageSender sender = new MockSender();

若你将对象硬编码在业务中 new EmailSender(),则测试中难以注入 Mock 对象。


5. 配合配置文件或 DI 容器灵活创建对象

工厂模式支持根据配置或上下文动态创建对象,是实现插件式架构、策略模式的关键支撑机制之一。

举例:​​​​​​​

// 从配置文件中读取 sender 类型
String senderType = config.get("message.sender"); // "sms", "email", "wechat"
MessageSender sender = SenderFactory.create(senderType);

这类工厂配合 Spring、Guice 等 IOC 容器,可实现全系统模块解耦、热插拔、模块化开发。


小结:工厂模式的五大动因

原因

描述

解耦创建与使用

避免调用方依赖具体类,提高模块独立性

隐藏复杂逻辑

封装对象构造的复杂性,简化业务逻辑

便于扩展

增加新产品无需修改已有代码,符合开闭原则

增强测试性与可替代性

接口编程易于 Mock 测试,提高可维护性

支持灵活配置 / 插件式架构

动态构建对象、支持配置驱动,适合策略模式、IOC 场景


三、生活中的工厂模式类比

你去星巴克点咖啡:

•你不需要知道咖啡是怎么煮出来的

•你只说:“我要一杯拿铁”

•店员(工厂)会帮你准备好对应的饮品

你只关心产品的“类型”,而不关心具体的构建细节,这就是“工厂模式”。


四、实际开发中,工厂模式适用于哪些场景?

•日志系统(返回不同日志记录器)

•数据库驱动(返回 MySQL、PostgreSQL 等连接对象)

•UI 框架(根据配置创建按钮、下拉框等组件)

•消息中间件封装(KafkaProducerFactory)


五、Java 中三种常见工厂模式及实战分析

1. 简单工厂模式(Simple Factory)

核心思想:由一个工厂类根据参数返回不同子类对象

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。

这会导致代码膨胀、难以维护。


2. 工厂方法模式(Factory Method)

核心思想:每种产品由自己的工厂类负责创建,工厂变得可扩展

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 个,新人很难理清结构。


3. 抽象工厂模式(Abstract Factory)

核心思想:为一组相关或相互依赖的产品提供一个统一的创建接口

适合于一整套产品族创建,如 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,回复“面试”即可获得!

你可能感兴趣的:(设计模式,java,开发语言,设计模式)