Java 设计模式之工厂模式:对象创建的艺术(含 UML 图解)

简介: 本文详解Java工厂模式三大形态:简单工厂、工厂方法与抽象工厂,结合UML图解与代码实例,剖析其核心思想——“创建与使用分离”。通过计算器、日志系统、电子设备等案例,深入讲解各模式的实现原理、适用场景及优缺点,并对比选择策略。最后揭示工厂模式在JDK和主流框架中的实际应用,帮助开发者掌握对象创建的艺术,提升代码扩展性与可维护性。(238字)

Java 设计模式之工厂模式:对象创建的艺术(含 UML 图解)

在软件开发中,对象的创建是最基础也最频繁的操作。如果直接在代码中到处使用new关键字创建对象,会导致代码耦合度高、扩展性差。工厂模式(Factory Pattern)通过将对象创建的逻辑封装在专门的工厂类中,实现了 "创建与使用分离",是解决对象创建问题的经典方案。

工厂模式并非单一模式,而是一个模式家族,包含简单工厂模式工厂方法模式抽象工厂模式三种形式。本文将详细讲解这三种模式的实现与应用场景。

一、工厂模式的核心思想

工厂模式属于创建型设计模式,它的核心思想是:将对象的创建过程封装起来,让客户端无需关心对象的具体创建细节,只需通过工厂获取所需对象

生活中的工厂模式例子随处可见:

  • 汽车工厂生产不同品牌的汽车,消费者无需知道汽车的生产细节,直接从工厂提车即可
  • 披萨店(工厂)制作不同口味的披萨,顾客只需点单(调用工厂方法),无需自己动手制作

工厂模式的核心价值在于:

  • 降低耦合:客户端与具体产品解耦,只依赖工厂和抽象产品
  • 提高扩展性:新增产品时只需扩展工厂,无需修改客户端
  • 统一管理:对象创建逻辑集中在工厂,便于维护和控制

二、简单工厂模式(Simple Factory)

简单工厂模式是工厂模式中最基础的形式,它通过一个工厂类根据传入的参数决定创建哪种产品对象。

核心角色

  1. 抽象产品(Product):定义产品的公共接口
  2. 具体产品(Concrete Product):实现抽象产品接口,是工厂创建的目标
  3. 工厂(Factory):根据参数创建具体产品的实例

UML 类图

+------------------+
|    Product       |
+------------------+
| + operation(): void |
+------------------+
        ^
        |
+------------------+  +------------------+
| ConcreteProductA |  | ConcreteProductB |
+------------------+  +------------------+
| + operation(): void |  | + operation(): void |
+------------------+  +------------------+
        ^                     ^
        |                     |
+------------------+
|    Factory       |
+------------------+
| + createProduct(type): Product |
+------------------+

代码实现:计算器工厂

以简单计算器为例,实现一个能创建加法、减法运算器的简单工厂:

1. 抽象产品(运算接口)

/**
 * 抽象产品:运算接口
 */
public interface Operation {
   
    double calculate(double a, double b);
}

2. 具体产品(加法、减法实现)

/**
 * 具体产品:加法运算
 */
public class AddOperation implements Operation {
   
    @Override
    public double calculate(double a, double b) {
   
        return a + b;
    }
}

/**
 * 具体产品:减法运算
 */
public class SubtractOperation implements Operation {
   
    @Override
    public double calculate(double a, double b) {
   
        return a - b;
    }
}

3. 工厂类(运算器工厂)

/**
 * 简单工厂:运算器工厂
 */
public class OperationFactory {
   
    /**
     * 根据类型创建运算器
     * @param type 运算类型:"+" "-"
     * @return 具体运算器实例
     */
    public static Operation createOperation(String type) {
   
        Operation operation = null;
        switch (type) {
   
            case "+":
                operation = new AddOperation();
                break;
            case "-":
                operation = new SubtractOperation();
                break;
            default:
                throw new IllegalArgumentException("不支持的运算类型");
        }
        return operation;
    }
}

4. 客户端使用

public class Client {
   
    public static void main(String[] args) {
   
        // 从工厂获取加法运算器
        Operation addOp = OperationFactory.createOperation("+");
        System.out.println("3 + 5 = " + addOp.calculate(3, 5)); // 8.0

        // 从工厂获取减法运算器
        Operation subOp = OperationFactory.createOperation("-");
        System.out.println("10 - 4 = " + subOp.calculate(10, 4)); // 6.0
    }
}

简单工厂模式的优缺点

  • 优点:实现简单,客户端无需知道产品创建细节
  • 缺点:违反开闭原则,新增产品需修改工厂类的判断逻辑,工厂类职责过重

三、工厂方法模式(Factory Method)

为了解决简单工厂模式的缺陷,工厂方法模式将工厂抽象化,为每个产品创建对应的工厂类,使新增产品时只需扩展工厂,无需修改原有代码。

核心角色

  1. 抽象产品(Product):定义产品的公共接口
  2. 具体产品(Concrete Product):实现抽象产品接口
  3. 抽象工厂(Abstract Factory):定义创建产品的接口
  4. 具体工厂(Concrete Factory):实现抽象工厂接口,创建具体产品

UML 类图

+------------------+       +------------------+
|    Product       |       |  AbstractFactory |
+------------------+       +------------------+
| + operation(): void |       | + createProduct(): Product |
+------------------+       +------------------+
        ^                           ^
        |                           |
+------------------+       +------------------+
| ConcreteProductA |<----->|  FactoryA        |
+------------------+       +------------------+
| + operation(): void |       | + createProduct(): Product |
+------------------+       +------------------+

+------------------+       +------------------+
| ConcreteProductB |<----->|  FactoryB        |
+------------------+       +------------------+
| + operation(): void |       | + createProduct(): Product |
+------------------+       +------------------+

代码实现:日志记录器工厂

以日志记录为例,实现文件日志和数据库日志的工厂方法模式:

1. 抽象产品(日志接口)

/**
 * 抽象产品:日志记录器
 */
public interface Logger {
   
    void log(String message);
}

2. 具体产品(文件日志、数据库日志)

/**
 * 具体产品:文件日志记录器
 */
public class FileLogger implements Logger {
   
    @Override
    public void log(String message) {
   
        System.out.println("文件日志:" + message);
    }
}

/**
 * 具体产品:数据库日志记录器
 */
public class DatabaseLogger implements Logger {
   
    @Override
    public void log(String message) {
   
        System.out.println("数据库日志:" + message);
    }
}

3. 抽象工厂(日志工厂接口)

/**
 * 抽象工厂:日志工厂
 */
public interface LoggerFactory {
   
    Logger createLogger();
}

4. 具体工厂(文件日志工厂、数据库日志工厂)

/**
 * 具体工厂:文件日志工厂
 */
public class FileLoggerFactory implements LoggerFactory {
   
    @Override
    public Logger createLogger() {
   
        // 可以在这里添加文件日志的初始化逻辑
        return new FileLogger();
    }
}

/**
 * 具体工厂:数据库日志工厂
 */
public class DatabaseLoggerFactory implements LoggerFactory {
   
    @Override
    public Logger createLogger() {
   
        // 可以在这里添加数据库连接等初始化逻辑
        return new DatabaseLogger();
    }
}

5. 客户端使用

public class Client {
   
    public static void main(String[] args) {
   
        // 创建文件日志工厂和日志记录器
        LoggerFactory fileFactory = new FileLoggerFactory();
        Logger fileLogger = fileFactory.createLogger();
        fileLogger.log("系统启动成功"); // 文件日志:系统启动成功

        // 创建数据库日志工厂和日志记录器
        LoggerFactory dbFactory = new DatabaseLoggerFactory();
        Logger dbLogger = dbFactory.createLogger();
        dbLogger.log("用户登录"); // 数据库日志:用户登录
    }
}

工厂方法模式的优缺点

  • 优点:符合开闭原则,新增产品只需新增对应的产品类和工厂类;单一职责,每个工厂只负责创建一种产品
  • 缺点:类数量增多,系统复杂度提高;客户端需要知道具体工厂才能获取对应产品

四、抽象工厂模式(Abstract Factory)

当需要创建一系列相互关联或依赖的产品时,抽象工厂模式应运而生。它提供一个接口,用于创建多个产品族中的产品对象。

核心概念

  • 产品族:同一工厂生产的、功能相关联的一组产品(如华为工厂生产的手机、平板)
  • 产品等级结构:同一类产品的不同实现(如手机有华为手机、苹果手机)

核心角色

  1. 抽象产品(Abstract Product):多个产品等级结构的接口
  2. 具体产品(Concrete Product):实现抽象产品接口
  3. 抽象工厂(Abstract Factory):声明创建多个产品族的方法
  4. 具体工厂(Concrete Factory):实现抽象工厂,创建同一产品族的产品

UML 类图

+------------------+  +------------------+
|    Phone         |  |    Tablet        |
+------------------+  +------------------+
| + call(): void   |  | + browse(): void |
+------------------+  +------------------+
        ^                     ^
        |                     |
+------------------+  +------------------+
| HuaweiPhone      |  | HuaweiTablet     |
+------------------+  +------------------+
| + call(): void   |  | + browse(): void |
+------------------+  +------------------+

+------------------+  +------------------+
| IPhone           |  | IPad             |
+------------------+  +------------------+
| + call(): void   |  | + browse(): void |
+------------------+  +------------------+

        ^                     ^
        |                     |
+------------------+
|  AbstractFactory |
+------------------+
| + createPhone(): Phone    |
| + createTablet(): Tablet  |
+------------------+
        ^
        |
+------------------+  +------------------+
| HuaweiFactory    |  | AppleFactory     |
+------------------+  +------------------+
| + createPhone(): Phone    |  | + createPhone(): Phone    |
| + createTablet(): Tablet  |  | + createTablet(): Tablet  |
+------------------+  +------------------+

代码实现:电子设备工厂

以华为和苹果的产品族为例,实现能生产手机和平板的抽象工厂:

1. 抽象产品(手机、平板接口)

/**
 * 抽象产品:手机
 */
public interface Phone {
   
    void call();
}

/**
 * 抽象产品:平板
 */
public interface Tablet {
   
    void browse();
}

2. 具体产品(华为 / 苹果的手机和平板)

/**
 * 具体产品:华为手机
 */
public class HuaweiPhone implements Phone {
   
    @Override
    public void call() {
   
        System.out.println("用华为手机打电话");
    }
}

/**
 * 具体产品:华为平板
 */
public class HuaweiTablet implements Tablet {
   
    @Override
    public void browse() {
   
        System.out.println("用华为平板浏览网页");
    }
}

/**
 * 具体产品:苹果手机
 */
public class IPhone implements Phone {
   
    @Override
    public void call() {
   
        System.out.println("用iPhone打电话");
    }
}

/**
 * 具体产品:苹果平板
 */
public class IPad implements Tablet {
   
    @Override
    public void browse() {
   
        System.out.println("用iPad浏览网页");
    }
}

3. 抽象工厂(电子设备工厂接口)

/**
 * 抽象工厂:电子设备工厂
 */
public interface ElectronicFactory {
   
    Phone createPhone();  // 生产手机
    Tablet createTablet();// 生产平板
}

4. 具体工厂(华为工厂、苹果工厂)

/**
 * 具体工厂:华为工厂
 */
public class HuaweiFactory implements ElectronicFactory {
   
    @Override
    public Phone createPhone() {
   
        return new HuaweiPhone();
    }

    @Override
    public Tablet createTablet() {
   
        return new HuaweiTablet();
    }
}

/**
 * 具体工厂:苹果工厂
 */
public class AppleFactory implements ElectronicFactory {
   
    @Override
    public Phone createPhone() {
   
        return new IPhone();
    }

    @Override
    public Tablet createTablet() {
   
        return new IPad();
    }
}

5. 客户端使用

public class Client {
   
    public static void main(String[] args) {
   
        // 使用华为工厂生产华为产品族
        ElectronicFactory huaweiFactory = new HuaweiFactory();
        Phone huaweiPhone = huaweiFactory.createPhone();
        Tablet huaweiTablet = huaweiFactory.createTablet();
        huaweiPhone.call();    // 用华为手机打电话
        huaweiTablet.browse(); // 用华为平板浏览网页

        // 使用苹果工厂生产苹果产品族
        ElectronicFactory appleFactory = new AppleFactory();
        Phone iPhone = appleFactory.createPhone();
        Tablet iPad = appleFactory.createTablet();
        iPhone.call();         // 用iPhone打电话
        iPad.browse();         // 用iPad浏览网页
    }
}

抽象工厂模式的优缺点

  • 优点:便于管理同一产品族的产品;保证产品族内产品的兼容性;符合开闭原则(扩展产品族只需新增工厂)
  • 缺点:扩展新的产品等级结构困难(如新增手表产品,需修改所有工厂接口和实现)

五、三种工厂模式的对比与选择

模式 核心特点 适用场景 优缺点对比
简单工厂 一个工厂类创建所有产品 产品种类少,变化不频繁 实现简单但违反开闭原则
工厂方法 一个工厂对应一个产品 产品种类较多,需要灵活扩展 符合开闭原则但类数量增多
抽象工厂 一个工厂创建一个产品族 需要创建相互关联的产品组,强调产品族兼容性 适合产品族扩展,但难扩展新产品

选择建议

  • 简单场景用简单工厂,快速实现
  • 单一产品扩展用工厂方法,兼顾灵活与简单
  • 多产品族场景用抽象工厂,保证产品关联性

六、工厂模式在 Java 中的应用

  1. JDK 中的应用
    • java.util.Calendar:通过getInstance()方法(简单工厂)创建日历实例
    • java.sql.DriverManager:通过getConnection()获取不同数据库连接(工厂方法)
    • java.net.URLStreamHandlerFactory:创建不同协议的流处理器(抽象工厂)
  2. 框架中的应用
    • Spring 的BeanFactory:通过工厂模式创建和管理 Bean 对象
    • MyBatis 的SqlSessionFactory:创建SqlSession对象(工厂方法)

总结

工厂模式通过封装对象创建逻辑,完美诠释了 "创建与使用分离" 的设计思想。从简单工厂到抽象工厂,模式的复杂度逐渐增加,但灵活性和适用性也随之提升。

在实际开发中,不必盲目追求复杂模式,应根据业务场景选择最合适的实现:简单场景用简单工厂提高开发效率,复杂场景用工厂方法或抽象工厂保证扩展性。记住,设计模式的核心是解决问题,而非炫技。

掌握工厂模式,不仅能写出更优雅的代码,更能培养 "封装变化" 的设计思维 —— 这正是优秀程序员与普通程序员的重要区别。

目录
相关文章
|
3月前
|
设计模式 消息中间件 前端开发
Java 设计模式之中介者模式:解耦复杂交互的架构艺术(含 UML 图解)
中介者模式通过引入协调者解耦多个对象间的复杂交互,将网状依赖转化为星型结构。适用于聊天室、GUI事件系统等场景,提升可维护性与扩展性,但需防中介者过度膨胀。
331 3
|
3月前
|
设计模式 Java Spring
Java 设计模式之责任链模式:优雅处理请求的艺术
责任链模式通过构建处理者链,使请求沿链传递直至被处理,实现发送者与接收者的解耦。适用于审批流程、日志处理等多级处理场景,提升系统灵活性与可扩展性。
452 2
|
3月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
410 0
|
3月前
|
SQL 关系型数据库 MySQL
开源新发布|PolarDB-X v2.4.2开源生态适配升级
PolarDB-X v2.4.2开源发布,重点完善生态能力:新增客户端驱动、开源polardbx-proxy组件,支持读写分离与高可用;强化DDL变更、扩缩容等运维能力,并兼容MySQL主备复制及MCP AI生态。
开源新发布|PolarDB-X v2.4.2开源生态适配升级
|
3月前
|
数据采集 机器学习/深度学习 人工智能
什么是跨境电商采集器?一文带你看懂,从工具入门到场景案例!
跨境电商采集器是卖家抢占市场的秘密武器,可自动采集多平台商品数据,助力精准选品、竞品监控与批量上货。融合AI与RPA技术,实现全流程智能运营,提升效率,驱动增长,已成为全球化电商竞争的必备利器。
312 9
|
3月前
|
小程序 Java 关系型数据库
基于微信小程序的博物馆文创系统
本研究聚焦基于微信小程序的博物馆文创系统,结合Java、SpringBoot与MySQL技术,构建集文创销售、互动体验与文化传播于一体的数字化平台,提升用户体验与文化服务效能。
|
存储 安全 数据安全/隐私保护
Token 是什么?全面解析身份认证中的 Token 机制
本文全面解析Token在身份认证中的核心机制,涵盖JWT、Session Token、OAuth等类型,深入讲解其工作原理、安全性策略、生命周期管理及实际应用场景,助力开发者构建安全高效的现代Web应用认证体系。
2470 3
|
3月前
|
设计模式 算法 搜索推荐
Java 设计模式之策略模式:灵活切换算法的艺术
策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。
480 35
|
4月前
|
机器学习/深度学习 存储 自然语言处理
语义检索翻车?可能是你的Embedding模型没选对!
本文深入解析Embedding模型在RAG系统中的核心作用,涵盖其原理、类型、选型策略及实战建议。选对模型可显著提升语义检索准确性与效率,避免成本浪费。干货满满,值得收藏!
2568 52

热门文章

最新文章