火柴人武林大会
156.74M · 2026-02-04
工厂方法模式定义一个创建对象的接口(抽象工厂),但由子类决定实例化哪个类。它将对象的创建逻辑延迟到子类中,实现了 “创建责任” 与 “使用责任” 的彻底分离。
简单来说:父类只规定 “要创建什么类型的对象”,具体创建 “哪个具体对象” 交给子类来完成。
在学习工厂方法前,我们先理解它要解决的痛点 ——简单工厂模式的局限性:
if-else 或 switch),违反开闭原则(对扩展开放、对修改关闭);工厂方法模式的解决方案:
工厂方法模式的结构清晰,包含 4 个固定角色,缺一不可:
| 角色名称 | 核心职责 | 示例(以 “电子设备生产” 为例) |
|---|---|---|
| 抽象产品(Product) | 定义所有具体产品的公共接口 / 抽象类,规范产品的功能 | 抽象类 ElectronicDevice,包含抽象方法 powerOn()(开机) |
| 具体产品(Concrete Product) | 实现抽象产品的接口,是工厂方法模式的创建目标 | 类 Phone(手机)、Tablet(平板),均实现 powerOn() |
| 抽象工厂(Factory) | 定义创建具体产品的接口(含抽象方法 createProduct()),声明返回抽象产品类型 | 接口 DeviceFactory,含方法 createElectronicDevice() |
| 具体工厂(Concrete Factory) | 实现抽象工厂的接口,重写 createProduct() 方法,返回具体产品实例 | 类 PhoneFactory(创建 Phone)、TabletFactory(创建 Tablet) |
以 “电子设备生产” 为例,完整实现工厂方法模式:
规范所有电子设备的公共行为(如开机):
// 抽象产品:电子设备
public abstract class ElectronicDevice {
// 抽象方法:开机
public abstract void powerOn();
}
每个具体产品对应一种实际设备,实现抽象方法:
// 具体产品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,显示分屏界面");
}
}
声明创建产品的接口,返回抽象产品类型(依赖抽象而非具体):
// 抽象工厂:电子设备工厂
public interface DeviceFactory {
// 抽象方法:创建电子设备(返回抽象产品类型)
ElectronicDevice createElectronicDevice();
}
每个具体工厂对应一种具体产品,负责创建实例:
// 具体工厂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();
}
}
客户端只需依赖 “抽象工厂” 和 “抽象产品”,无需知道具体实现,实现解耦:
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 时) :
手机开机:显示品牌Logo,进入主屏幕
运行结果(TabletFactory 时) :
平板开机:自动连接WiFi,显示分屏界面
当满足以下任一条件时,优先使用工厂方法模式:
BeanFactory 就是工厂方法的典型应用)。经典实战案例:
Collection 接口:List、Set 是抽象产品,ArrayList、HashSet 是具体产品;Collection 的工厂方法(如 Arrays.asList())可视为简化的工厂实现;Logger 是抽象产品,ConsoleAppenderLogger、FileAppenderLogger 是具体产品,LoggerFactory 是抽象工厂的入口。| 优点 | 缺点 |
|---|---|
| 1. 符合开闭原则:新增产品只需加 “具体产品 + 具体工厂”,无需改原有代码;2. 解耦创建与使用:客户端只依赖抽象,不依赖具体实现,代码更灵活;3. 单一职责:每个具体工厂只负责创建一种产品,逻辑清晰。 | 1. 类数量增加:每新增一个产品,需对应新增一个具体工厂,可能导致类膨胀;2. 学习成本:相比简单工厂,需理解 “抽象工厂 + 抽象产品” 的多层结构,对新手不友好。 |
很多人会混淆 “简单工厂” 和 “工厂方法”,这里用一句话区分:
if-else 判断),违反开闭原则;简单工厂是 “工厂方法的简化版”,适合产品种类固定、不会频繁扩展的场景(如 JDK 中的 Calendar.getInstance());工厂方法则适合产品种类可能扩展的场景(如业务系统中的支付、登录方式)。