什么是工厂模式?3种实现方式的区别和特点?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于 Spring AI + Spring Boot3.x + JDK 21...点击查看;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot3.x + JDK 17...点击查看项目介绍; 演示链接: http://116.62.199.48:7070/;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

面试考察点

当面试官提出这个问题时,他不仅仅是在考察你是否背下了设计模式的定义,更是在评估你的以下几个维度的能力:

  1. 对面向对象设计原则的理解:你是否理解 “封装变化”、“针对接口编程” 等原则,并能将其应用于解耦对象创建逻辑。
  2. 对不同场景下解决方案的区分能力:三种工厂模式解决的是不同复杂度、不同维度的 “对象创建” 问题,能否准确区分是关键。
  3. 对设计模式演进脉络的掌握:从简单工厂到工厂方法再到抽象工厂,体现了设计模式是如何随着需求复杂度的增加而演进的。
  4. 实践经验与场景化思维:你是否能在实际项目中识别出需要使用工厂模式的场景,并选择合适的一种。

核心答案

工厂模式 是一种创建型设计模式,其核心思想是将对象的创建过程封装起来,让客户端不直接依赖具体实现类,而是依赖一个抽象的创建接口,从而实现解耦。

三种主要的实现方式及其核心区别如下:

  1. 简单工厂模式 (Simple Factory):一个工厂类根据传入的参数,通过 if/elseswitch 来创建并返回不同的产品对象。它不属于 GoF 23 种设计模式,更像是一种编程习惯。
  2. 工厂方法模式 (Factory Method):定义一个用于创建对象的接口(抽象工厂),但让子类决定实例化哪一个具体产品类。工厂方法使一个类的实例化延迟到其子类。核心是 “类的” 解耦
  3. 抽象工厂模式 (Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。核心是“产品族”的创建,比工厂方法的维度更高。

简单比喻:

  • 简单工厂:一个万能工具,按按钮出不同工具。
  • 工厂方法:各家工具店(子类)都承诺能提供锤子(产品接口),但A店出木工锤,B店出石工锤。
  • 抽象工厂:一个家具厂(抽象工厂)承诺能生产一整套现代风格家具(产品族);另一个家具厂则生产一整套古典风格家具。

深度解析

原理/机制与代码示例

1. 简单工厂模式 它负责集中处理所有产品的创建逻辑。当新增产品时,必须修改工厂类的代码(增加 if/else),这违反了开闭原则

// 产品接口
interface Chart {
    void display();
}

// 具体产品
class LineChart implements Chart { /* ... */ }
class PieChart implements Chart { /* ... */ }

// 简单工厂
public class ChartFactory {
    public static Chart getChart(String type) {
        if (type.equalsIgnoreCase("line")) {
            return new LineChart();
        } else if (type.equalsIgnoreCase("pie")) {
            return new PieChart();
        }
        throw new IllegalArgumentException("Unsupported chart type.");
    }
}

// 客户端使用
Chart chart = ChartFactory.getChart("line");
chart.display();

2. 工厂方法模式 它将具体产品的创建延迟到子类。每新增一个产品,就新增一个对应的具体工厂类,符合开闭原则。

// 抽象工厂
interface ChartFactory {
    Chart createChart();
}

// 具体工厂
class LineChartFactory implements ChartFactory {
    @Override
    public Chart createChart() {
        return new LineChart(); // 专注创建LineChart
    }
}
class PieChartFactory implements ChartFactory {
    @Override
    public Chart createChart() {
        return new PieChart(); // 专注创建PieChart
    }
}

// 客户端使用
ChartFactory factory = new LineChartFactory();
Chart chart = factory.createChart(); // 创建的是LineChart
chart.display();

3. 抽象工厂模式 它用于创建产品族(一系列相关的产品)。一个抽象工厂定义能创建哪些产品,每个具体工厂负责一个产品族的具体实现。

// 抽象产品族:UI组件
interface Button { void render(); }
interface TextField { void input(); }

// 抽象工厂:能创建一套UI组件
interface UIFactory {
    Button createButton();
    TextField createTextField();
}

// 具体产品族1:Mac风格
class MacButton implements Button { /* ... */ }
class MacTextField implements TextField { /* ... */ }
class MacUIFactory implements UIFactory {
    public Button createButton() { return new MacButton(); }
    public TextField createTextField() { return new MacTextField(); }
}

// 具体产品族2:Windows风格
class WinButton implements Button { /* ... */ }
class WinTextField implements TextField { /* ... */ }
class WinUIFactory implements UIFactory {
    public Button createButton() { return new WinButton(); }
    public TextField createTextField() { return new WinTextField(); }
}

// 客户端使用:轻松切换整套UI风格
UIFactory factory = new MacUIFactory(); // 只需改这一行
Button btn = factory.createButton(); // 得到Mac风格按钮
TextField field = factory.createTextField(); // 得到Mac风格输入框

对比分析与适用场景

特性简单工厂工厂方法抽象工厂
核心角色工厂类、产品接口、具体产品抽象工厂、具体工厂、产品接口、具体产品抽象工厂、具体工厂、抽象产品族、具体产品族
扩展性差(需修改工厂类)好(新增产品+工厂类)好(新增产品族+工厂类)
复杂度
遵循开闭原则
解决问题维度单个产品的创建选择单个产品的创建延迟与扩展多个相关产品(产品族) 的成套创建
典型应用场景JDK Calendar.getInstance()NumberFormat.getInstance()Spring Framework 中的 BeanFactory, 日志框架的 AppenderFactory跨平台UI库, 数据库访问层(连接、命令、适配器等组件的统一切换)

最佳实践与常见误区

  • 最佳实践

    1. 优先使用工厂方法:在大多数需要解耦对象创建的场景下,工厂方法模式是更优雅、更符合设计原则的选择。
    2. 理解抽象工厂的 “产品族”:不要滥用抽象工厂。只有当系统中存在多个产品等级结构(如不同操作系统下的按钮、文本框、菜单),并且你希望一次性地使用同一个产品族中的产品时,才考虑它。
    3. 结合依赖注入(DI):现代框架(如 Spring)的 IoC 容器本质上是超级工厂,它利用工厂模式的思想,通过配置和注解来管理和创建所有 Bean,这是工厂模式在生产环境中的终极实践。
  • 常见误区

    1. 混淆工厂方法与抽象工厂:记住,工厂方法关注 “一个产品” 的创建扩展;抽象工厂关注 “一系列产品” 的创建和组合。
    2. 为了模式而模式:如果产品创建逻辑非常简单,直接使用 new 是最清晰的选择。引入模式会带来额外的抽象层,增加复杂度。
    3. 认为简单工厂一无是处:虽然它不符合开闭原则,但在内部工具类、创建逻辑稳定且简单的场景下,它代码直观,完全可以使用。

总结

工厂模式的本质是通过引入一个抽象层来封装对象的创建过程,从而实现客户端代码与具体产品类的解耦。简单工厂易于理解但扩展性差;工厂方法通过子类化解决了扩展问题;而抽象工厂则将解耦的维度从 “单个产品” 提升到了 “产品族”,是构建大型、可配置系统(如 UI 框架、ORM)的利器。