Java 工厂方法模式:解耦对象创建的优雅方案

目录

前言

一、什么是工厂方法模式

二、工厂方法模式的核心结构

[1. 抽象产品(Product)](#1. 抽象产品(Product))

[2. 具体产品(Concrete Product)](#2. 具体产品(Concrete Product))

[3. 抽象工厂(Factory)](#3. 抽象工厂(Factory))

[4. 具体工厂(Concrete Factory)](#4. 具体工厂(Concrete Factory))

三、Java实战:工厂方法模式代码实现

[1. 定义抽象产品(日志接口)](#1. 定义抽象产品(日志接口))

[2. 实现具体产品(文件日志、控制台日志)](#2. 实现具体产品(文件日志、控制台日志))

[3. 定义抽象工厂(日志工厂接口)](#3. 定义抽象工厂(日志工厂接口))

[4. 实现具体工厂(文件日志工厂、控制台日志工厂)](#4. 实现具体工厂(文件日志工厂、控制台日志工厂))

[5. 客户端调用(使用工厂创建产品)](#5. 客户端调用(使用工厂创建产品))

运行结果

扩展新产品(数据库日志)

四、工厂方法模式的应用场景

五、工厂方法模式的优缺点

优点

缺点

六、工厂方法模式与简单工厂模式的区别

七、总结

前言

作为Java开发者,我们日常编码中总会面临对象创建的场景。如果直接通过new关键字实例化对象,会导致代码耦合度偏高,后续需求迭代时修改成本激增。工厂方法模式作为创建型设计模式的核心成员,正是为解决对象创建与使用的解耦问题而生。本文将从定义、结构、实现、应用场景等维度,带你彻底吃透工厂方法模式,助力写出更灵活、可维护的Java代码。

一、什么是工厂方法模式

工厂方法模式(Factory Method Pattern)的核心定义:定义一个创建对象的接口(抽象工厂),让子类决定实例化哪个类(具体产品),使一个类的实例化延迟到其子类。简单来说,就是"把对象创建的活儿交给子类来做",通过抽象工厂约定创建逻辑,由具体工厂负责具体产品的实例化,彻底隔绝产品创建与产品使用的直接关联。

它是对"简单工厂模式"的优化升级------简单工厂模式通过一个工厂类集中创建所有产品,违背了"开闭原则"(新增产品需修改工厂代码),而工厂方法模式将工厂抽象化,新增产品时只需新增对应具体工厂,无需改动原有代码,完美契合开闭原则,是更具扩展性的创建方案。

二、工厂方法模式的核心结构

工厂方法模式包含4个核心角色,各角色职责清晰,协同完成对象创建与解耦,结合Java场景拆解如下:

1. 抽象产品(Product)

定义所有具体产品的公共接口或抽象类,规范产品的核心行为。它是工厂方法模式中产品的"顶层规范",确保所有具体产品都具备统一的功能,便于客户端统一调用。

2. 具体产品(Concrete Product)

抽象产品的具体实现类,是工厂方法模式最终要创建的对象。每个具体产品对应一个具体工厂,由具体工厂负责其实例化。

3. 抽象工厂(Factory)

定义创建产品的抽象方法,该方法返回抽象产品类型,不涉及具体产品的创建逻辑。抽象工厂可以是接口,也可以是抽象类,其核心职责是约定"如何创建产品",而非"创建哪种产品"。

4. 具体工厂(Concrete Factory)

抽象工厂的实现类,重写抽象工厂的创建方法,负责实例化具体产品。每个具体工厂对应一种具体产品,新增产品时,只需新增对应的具体产品类和具体工厂类即可。

三、Java实战:工厂方法模式代码实现

我们以"日志记录器"为例,实现工厂方法模式。需求:支持两种日志记录方式(文件日志、控制台日志),后续可灵活扩展数据库日志等新类型,且新增时不修改原有代码。

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

java 复制代码
/**
 * 抽象产品:日志记录器接口
 * 定义所有日志的公共行为
 */
public interface Logger {
    // 日志记录方法
    void log(String message);
}

2. 实现具体产品(文件日志、控制台日志)

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

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

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

java 复制代码
/**
 * 抽象工厂:日志工厂接口
 * 定义创建日志对象的抽象方法
 */
public interface LoggerFactory {
    // 抽象工厂方法,返回抽象产品类型
    Logger createLogger();
}

4. 实现具体工厂(文件日志工厂、控制台日志工厂)

java 复制代码
/**
 * 具体工厂1:文件日志工厂
 * 负责创建文件日志对象
 */
public class FileLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        // 可在此处添加文件日志的初始化逻辑(如创建文件、配置路径等)
        return new FileLogger();
    }
}

/**
 * 具体工厂2:控制台日志工厂
 * 负责创建控制台日志对象
 */
public class ConsoleLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        // 可在此处添加控制台日志的初始化逻辑
        return new ConsoleLogger();
    }
}

5. 客户端调用(使用工厂创建产品)

java 复制代码
/**
 * 客户端:使用工厂方法模式创建日志对象
 */
public class Client {
    public static void main(String[] args) {
        // 1. 创建具体工厂(可根据配置动态选择工厂,无需硬编码)
        LoggerFactory factory = new ConsoleLoggerFactory();
        // 2. 通过工厂创建产品(面向抽象产品编程,无需关注具体实现)
        Logger logger = factory.createLogger();
        // 3. 使用产品功能
        logger.log("工厂方法模式实战演示");

        // 切换为文件日志,只需修改具体工厂,无需改动其他代码
        factory = new FileLoggerFactory();
        logger = factory.createLogger();
        logger.log("切换为文件日志记录");
    }
}

运行结果

java 复制代码
控制台日志:工厂方法模式实战演示
文件日志:切换为文件日志记录

扩展新产品(数据库日志)

若需新增数据库日志,只需新增具体产品和具体工厂,无需修改原有代码,完全符合开闭原则:

java 复制代码
// 新增具体产品:数据库日志
public class DatabaseLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("数据库日志:" + message);
    }
}

// 新增具体工厂:数据库日志工厂
public class DatabaseLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        // 数据库日志初始化逻辑(如连接数据库)
        return new DatabaseLogger();
    }
}

// 客户端调用新增产品,无需修改原有代码
LoggerFactory dbFactory = new DatabaseLoggerFactory();
Logger dbLogger = dbFactory.createLogger();
dbLogger.log("数据库日志记录");

四、工厂方法模式的应用场景

工厂方法模式适合以下Java开发场景,核心是解决"对象创建与使用解耦"和"灵活扩展"问题:

  1. 产品类型不确定,需灵活扩展:如上述日志案例,后续可能新增多种日志类型,工厂方法可快速适配,无需改动原有逻辑。

  2. 对象创建逻辑复杂:当对象创建需要初始化配置、依赖其他对象、处理异常等复杂逻辑时,可将这些逻辑封装在具体工厂中,简化客户端代码。

  3. 面向抽象编程,降低耦合:客户端只需面向抽象产品和抽象工厂编程,无需关注具体产品的实现细节,符合"依赖倒置原则"。

  4. 框架中的应用:Java主流框架中大量使用工厂方法模式,如Spring的BeanFactory(抽象工厂),通过getBean()方法(工厂方法)创建Bean实例,不同的BeanFactory实现类对应不同的Bean创建逻辑。

五、工厂方法模式的优缺点

优点

  • 符合开闭原则:新增产品时,只需新增具体产品和具体工厂,无需修改原有代码,扩展性强。

  • 解耦创建与使用:将对象创建逻辑封装在工厂中,客户端无需关注创建细节,只需使用产品。

  • 符合依赖倒置原则:依赖抽象而非具体,客户端依赖抽象工厂和抽象产品,降低代码耦合度。

  • 单一职责原则:每个具体工厂只负责创建一种具体产品,职责清晰,便于维护。

缺点

  • 类数量激增:每新增一种产品,需对应新增一个具体产品类和一个具体工厂类,增加系统复杂度。

  • 系统灵活性依赖抽象层:抽象工厂和抽象产品的设计需精准,若后续需修改抽象层,成本较高。

  • 简单场景冗余:对于产品类型固定、无需扩展的简单场景,使用工厂方法会增加代码冗余,不如直接new对象简洁。

六、工厂方法模式与简单工厂模式的区别

很多Java开发者会混淆两者,核心区别在于"是否遵循开闭原则"和"工厂的职责范围":

对比维度 简单工厂模式 工厂方法模式
工厂数量 一个统一的工厂类 一个抽象工厂 + 多个具体工厂
开闭原则 违背:新增产品需修改工厂代码 遵循:新增产品只需新增工厂和产品
职责划分 工厂职责过重,负责所有产品创建 职责拆分,每个工厂只负责一种产品
扩展性 差,修改原有代码易引发风险 好,灵活扩展,无侵入式修改

七、总结

工厂方法模式的核心价值,是将对象的"创建权"与"使用权"分离,通过抽象层定义规范,让子类承担具体创建职责,从而实现代码解耦与灵活扩展。它是Java设计模式中"创建型模式"的基础,也是理解抽象工厂模式、建造者模式的前提。

在实际开发中,我们无需盲目使用工厂方法模式------对于简单场景,直接new对象更高效;但对于产品类型多变、创建逻辑复杂的场景,工厂方法模式能显著提升代码的可维护性和扩展性,尤其在框架开发中(如Spring、MyBatis),其应用随处可见。

作为Java学者,掌握工厂方法模式,不仅能写出更优雅的代码,更能理解主流框架的设计思想,为后续学习更复杂的设计模式打下坚实基础。

相关推荐
小楼v5 小时前
使用Nacos实现动态IP黑名单过滤
java·后端·微服务·nacos
鱼跃鹰飞5 小时前
Leetcode会员尊享面试100题:333.最大二叉搜索子树
数据结构·算法·leetcode·面试
日拱一卒——功不唐捐5 小时前
交换排序:冒泡排序和快速排序(C语言)
c语言·数据结构·算法
2301_790300965 小时前
C++与物联网开发
开发语言·c++·算法
鱼跃鹰飞5 小时前
Leetcode会员尊享面试100题:255.验证二叉搜索树的前序遍历序列
算法·leetcode·面试
A懿轩A5 小时前
【Java 基础编程】Java 运算符完全指南:算术/关系/逻辑/位运算与优先级,避免常见坑
java·开发语言
IRevers5 小时前
RF-DETR:第一个在COCO上突破60AP的DETR(含检测和分割推理)
图像处理·人工智能·python·深度学习·目标检测·计算机视觉
专注echarts研发20年5 小时前
如何实现 QLabel 的 Click 事件?Qt 富文本超链接优雅方案
开发语言·qt
时艰.5 小时前
Java 并发编程核心知识点
java·开发语言