第 2 天:工厂方法模式(Factory Method Pattern)—— 创建型模式

第 2 天:工厂方法模式(Factory Method Pattern)------ 创建型模式

1. 核心定义

工厂方法模式定义一个创建对象的接口 (抽象工厂),但由子类决定实例化哪个类。它将对象的创建逻辑延迟到子类中,实现了 "创建责任" 与 "使用责任" 的彻底分离。

简单来说:父类只规定 "要创建什么类型的对象",具体创建 "哪个具体对象" 交给子类来完成。

2. 解决的核心问题

在学习工厂方法前,我们先理解它要解决的痛点 ------简单工厂模式的局限性

  • 简单工厂模式通过一个 "万能工厂类" 创建所有对象,若新增产品(如从 "手机" 新增 "平板"),必须修改工厂类的逻辑(添加 if-elseswitch),违反开闭原则(对扩展开放、对修改关闭);
  • 工厂类职责过重,所有产品的创建逻辑集中在一个类中,代码臃肿且不易维护。

工厂方法模式的解决方案:

  • 将 "万能工厂" 拆分为 "抽象工厂 + 多个具体工厂",每个具体工厂只负责创建一种具体产品;
  • 新增产品时,只需新增 "具体产品类 + 对应的具体工厂类",无需修改原有代码,完全符合开闭原则。

3. 核心角色(4 个)

工厂方法模式的结构清晰,包含 4 个固定角色,缺一不可:

角色名称 核心职责 示例(以 "电子设备生产" 为例)
抽象产品(Product) 定义所有具体产品的公共接口 / 抽象类,规范产品的功能 抽象类 ElectronicDevice,包含抽象方法 powerOn()(开机)
具体产品(Concrete Product) 实现抽象产品的接口,是工厂方法模式的创建目标 Phone(手机)、Tablet(平板),均实现 powerOn()
抽象工厂(Factory) 定义创建具体产品的接口(含抽象方法 createProduct()),声明返回抽象产品类型 接口 DeviceFactory,含方法 createElectronicDevice()
具体工厂(Concrete Factory) 实现抽象工厂的接口,重写 createProduct() 方法,返回具体产品实例 PhoneFactory(创建 Phone)、TabletFactory(创建 Tablet

4. 实现步骤与代码示例(Java)

以 "电子设备生产" 为例,完整实现工厂方法模式:

步骤 1:定义抽象产品(ElectronicDevice)

规范所有电子设备的公共行为(如开机):

java 复制代码
// 抽象产品:电子设备
public abstract class ElectronicDevice {
    // 抽象方法:开机
    public abstract void powerOn();
}

步骤 2:实现具体产品(Phone、Tablet)

每个具体产品对应一种实际设备,实现抽象方法:

java 复制代码
// 具体产品1:手机
public class Phone extends ElectronicDevice {
    @Override
    public void powerOn() {
        System.out.println("手机开机:显示品牌Logo,进入主屏幕");
    }
}

// 具体产品2:平板
public class Tablet extends ElectronicDevice {
    @Override
    public void powerOn() {
        System.out.println("平板开机:自动连接WiFi,显示分屏界面");
    }
}

步骤 3:定义抽象工厂(DeviceFactory)

声明创建产品的接口,返回抽象产品类型(依赖抽象而非具体):

csharp 复制代码
// 抽象工厂:电子设备工厂
public interface DeviceFactory {
    // 抽象方法:创建电子设备(返回抽象产品类型)
    ElectronicDevice createElectronicDevice();
}

步骤 4:实现具体工厂(PhoneFactory、TabletFactory)

每个具体工厂对应一种具体产品,负责创建实例:

java 复制代码
// 具体工厂1:手机工厂
public class PhoneFactory implements DeviceFactory {
    @Override
    public ElectronicDevice createElectronicDevice() {
        // 只负责创建Phone实例
        return new Phone();
    }
}

// 具体工厂2:平板工厂
public class TabletFactory implements DeviceFactory {
    @Override
    public ElectronicDevice createElectronicDevice() {
        // 只负责创建Tablet实例
        return new Tablet();
    }
}

步骤 5:客户端使用(创建与使用分离)

客户端只需依赖 "抽象工厂" 和 "抽象产品",无需知道具体实现,实现解耦:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 1. 选择具体工厂(如需要手机,就用PhoneFactory)
        DeviceFactory factory = new PhoneFactory(); 
        // DeviceFactory factory = new TabletFactory(); // 切换为平板工厂,只需改这一行
        
        // 2. 通过工厂创建产品(返回抽象产品类型,无需关注具体是Phone还是Tablet)
        ElectronicDevice device = factory.createElectronicDevice();
        
        // 3. 使用产品(调用抽象方法,行为由具体产品决定)
        device.powerOn(); 
    }
}

运行结果(PhoneFactory 时)

plaintext 复制代码
手机开机:显示品牌Logo,进入主屏幕

运行结果(TabletFactory 时)

plaintext 复制代码
平板开机:自动连接WiFi,显示分屏界面

5. 应用场景

当满足以下任一条件时,优先使用工厂方法模式:

  1. 产品种类可能扩展:如系统需支持多种支付方式(微信支付、支付宝支付)、多种日志输出(文件日志、控制台日志),后续可能新增更多类型;
  2. 创建逻辑复杂:如创建对象前需初始化配置、连接资源(如数据库驱动创建),需将复杂逻辑封装在具体工厂中;
  3. 客户端无需关注创建细节 :如框架开发中,用户只需调用 API 获取对象,无需知道对象的创建过程(如 Spring 中的 BeanFactory 就是工厂方法的典型应用)。

经典实战案例

  • Java 中的 Collection 接口:ListSet 是抽象产品,ArrayListHashSet 是具体产品;Collection 的工厂方法(如 Arrays.asList())可视为简化的工厂实现;
  • 日志框架 Logback/Log4j:Logger 是抽象产品,ConsoleAppenderLoggerFileAppenderLogger 是具体产品,LoggerFactory 是抽象工厂的入口。

6. 优缺点分析

优点 缺点
1. 符合开闭原则:新增产品只需加 "具体产品 + 具体工厂",无需改原有代码;2. 解耦创建与使用:客户端只依赖抽象,不依赖具体实现,代码更灵活;3. 单一职责:每个具体工厂只负责创建一种产品,逻辑清晰。 1. 类数量增加:每新增一个产品,需对应新增一个具体工厂,可能导致类膨胀;2. 学习成本:相比简单工厂,需理解 "抽象工厂 + 抽象产品" 的多层结构,对新手不友好。

7. 与简单工厂模式的核心区别

很多人会混淆 "简单工厂" 和 "工厂方法",这里用一句话区分:

  • 简单工厂 :1 个工厂 → 生产 N 种产品(用 if-else 判断),违反开闭原则;
  • 工厂方法:N 个工厂 → 生产 N 种产品(1 个工厂对应 1 种产品),符合开闭原则。

简单工厂是 "工厂方法的简化版",适合产品种类固定、不会频繁扩展的场景(如 JDK 中的 Calendar.getInstance());工厂方法则适合产品种类可能扩展的场景(如业务系统中的支付、登录方式)。

相关推荐
回家路上绕了弯8 分钟前
分布式事务TCC详解:高并发场景下的柔性事务最优解?
分布式·后端
Coder_Boy_9 分钟前
基于DDD+Spring Boot 3.2+LangChain4j构建企业级智能客服系统 版本升级
java·人工智能·spring boot·后端·langchain
武昌库里写JAVA14 分钟前
vue+iview+node+express实现文件上传,显示上传进度条,实时计算上传速度
java·vue.js·spring boot·后端·sql
问道飞鱼21 分钟前
【工具知识】在 Spring Boot 项目中结合 IntelliJ IDEA 实现不同环境配置文件选择
java·spring boot·intellij-idea·多环境
java坤坤30 分钟前
Elasticsearch Java实战手册:搭建、条件构建与分页优化
java·elasticsearch
小梁努力敲代码43 分钟前
Java多线程--单例模式
java·开发语言
老华带你飞1 小时前
学生宿舍管理|基于java + vue学生宿舍管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
Filotimo_1 小时前
在java后端开发中,redis的用处
java·开发语言·redis
lkbhua莱克瓦241 小时前
TCP通信练习4-上传文件名重复问题
java·网络·网络协议·tcp/ip·tcp
INGg__1 小时前
Java面试现场:从简单到复杂
java·面试·技术