工厂方法模式(Factory Method Pattern)
工厂方法模式是创建型设计模式的核心成员,其核心目标是定义一个创建对象的接口,但让实现这个接口的子类决定实例化哪个类,从而将对象的创建延迟到子类。它如同现实中的 “汽车工厂”—— 抽象工厂定义 “生产汽车” 的标准,具体工厂(如奔驰工厂、宝马工厂)分别负责生产对应的汽车,新增车型时只需新增对应的工厂,无需修改原有工厂逻辑。
public interface ShirtProducer {
void produceShirt();
}
public class ManShirtProducer implements ShirtProducer {
@Override
public void produceShirt() {
System.out.println("produce man shirt.");
}
}
public class WomanShirtProducer implements ShirtProducer {
@Override
public void produceShirt() {
System.out.println("produce woman shirt.");
}
}
简单工厂模式
public class SimpleShirtFactory {
public ShirtProducer produce(String shirtType) {
if ("t-shirt".equals(shirtType)) {
return new WomanShirtProducer();
} else {
return new ManShirtProducer();
}
}
}
简单工厂(反射)
public class ReflectSimpleShirtFactory {
public ShirtProducer produce(String shirtType)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> ShirtProducer = Class.forName(shirtType);
return (ShirtProducer) ShirtProducer.newInstance();
}
}
多个工厂方法模式
对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
public class MultiShirtFactory {
public ShirtProducer produceManShirt() {
return new ManShirtProducer();
}
public ShirtProducer produceWomanShirt() {
return new WomanShirtProducer();
}
}
静态工厂方法模式
将多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
public class StaticMultiShirtFactory {
public static ShirtProducer produceShirt() {
return new ManShirtProducer();
}
public static ShirtProducer produceTShirt() {
return new WomanShirtProducer();
}
}
public class ShirtFactoryMain {
public static void main(String[] args) {
System.out.println("普通工厂模式");
SimpleShirtFactory shirtFactory1 = new SimpleShirtFactory();
ShirtProducer shirtProducer1 = shirtFactory1.produce("shirt");
shirtProducer1.produceShirt();
try {
System.out.println("普通工厂模式(反射)");
ReflectSimpleShirtFactory shirtFactory11 = new ReflectSimpleShirtFactory();
ShirtProducer shirtProducer11 = shirtFactory11.produce(ManShirtProducer.class.getName());
shirtProducer11.produceShirt();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("多工厂方法模式");
MultiShirtFactory shirtFactory2 = new MultiShirtFactory();
ShirtProducer shirtProducer2 = shirtFactory2.produceManShirt();
shirtProducer2.produceShirt();
System.out.println("静态工厂方法模式");
ShirtProducer shirtProducer3 = StaticMultiShirtFactory.produceShirt();
shirtProducer3.produceShirt();
}
}
一、工厂方法模式核心概念(通用)
1. 定义
定义一个用于创建对象的接口(抽象工厂),让子类(具体工厂)决定实例化哪一个类(具体产品)。工厂方法使一个类的实例化延迟到其子类。
2. 意图
- 解决简单工厂的扩展性问题:简单工厂模式中,新增产品需修改工厂类逻辑(违反 “开闭原则”);工厂方法模式将产品创建逻辑分散到具体工厂子类,新增产品只需新增子类,无需修改原有代码。
- 分离对象创建与使用:客户端只需关心抽象产品和抽象工厂,无需知道具体产品的类名和创建细节(如 “我要一辆车”,无需知道是奔驰还是宝马的生产过程)。
- 支持多态创建:不同具体工厂可创建不同类型的产品,客户端通过切换具体工厂实现产品的动态切换(如从 “奔驰工厂” 切换到 “宝马工厂”,即可获得不同产品)。
3. 通用核心组件
工厂方法模式通过 “抽象工厂定义接口,具体工厂实现创建逻辑” 实现对象创建的延迟,包含 4 个核心角色:
| 角色名称 | 职责描述 |
|---|---|
| Product(抽象产品) | 定义所有产品的共同接口或抽象类,声明产品的核心业务方法(如汽车的 “行驶” 方法)。 |
| ConcreteProduct(具体产品) | 实现抽象产品接口,是工厂方法模式的创建目标(如奔驰车、宝马车)。 |
| Factory(抽象工厂) | 声明工厂方法(factoryMethod()),返回一个 Product 类型的对象。抽象工厂可定义默认实现(可选),或仅作为接口。 |
| ConcreteFactory(具体工厂) | 继承或实现抽象工厂,重写工厂方法,返回具体产品实例(如BenzFactory的createCar()返回Benz对象)。 |
二、工厂方法模式详细解析(以 “汽车生产” 为例)
以 “汽车生产系统” 为场景:系统需支持多种汽车(奔驰、宝马)的生产,且未来可能新增更多品牌(如奥迪)。若用简单工厂,新增品牌需修改CarFactory的createCar()方法(添加if-else);工厂方法模式通过BenzFactory、BMWFactory等具体工厂分别生产对应汽车,新增奥迪时只需新增Audi(具体产品)和AudiFactory(具体工厂),无需修改现有代码。
1. 结构
- Product(抽象产品):
Car,定义drive()方法(汽车行驶)。 - ConcreteProduct(具体产品):
Benz(奔驰)、BMW(宝马),实现drive()方法(具体行驶逻辑)。 - Factory(抽象工厂):
CarFactory,声明createCar()方法(返回Car对象)。 - ConcreteFactory(具体工厂):
BenzFactory、BMWFactory,重写createCar(),分别返回Benz、BMW实例。
2. 类图(Mermaid)
classDiagram
%% 抽象产品:汽车接口
class Car {
<<Interface>>
+drive(): void // 汽车行驶
}
%% 具体产品1:奔驰车
class Benz {
+drive(): void // 实现奔驰行驶逻辑
}
%% 具体产品2:宝马车
class BMW {
+drive(): void // 实现宝马行驶逻辑
}
%% 抽象工厂:汽车工厂接口
class CarFactory {
<<Interface>>
+createCar(): Car // 工厂方法:创建汽车
}
%% 具体工厂1:奔驰工厂
class BenzFactory {
+createCar(): Car // 实现:返回Benz实例
}
%% 具体工厂2:宝马工厂
class BMWFactory {
+createCar(): Car // 实现:返回BMW实例
}
%% 客户端:使用工厂和产品
class Client {
+useCar(): void
}
%% 关系梳理
%% 具体产品实现抽象产品
Car <|-- Benz
Car <|-- BMW
%%具体工厂实现抽象工厂
CarFactory <|-- BenzFactory
CarFactory <|-- BMWFactory
BenzFactory --> Benz : 创建(返回实例)
BMWFactory --> BMW : 创建(返回实例)
Client --> CarFactory : 依赖抽象工厂
Client --> Car : 依赖抽象产品
3. 时序图(Mermaid)
以 “客户端通过奔驰工厂创建并使用奔驰车” 为例,展示工厂方法模式的调用流程:
sequenceDiagram
participant Client(客户端)
participant BenzFactory(具体工厂:奔驰工厂)
participant Benz(具体产品:奔驰车)
participant CarFactory(抽象工厂)
participant Car(抽象产品)
%% 1. 客户端选择具体工厂(奔驰工厂)
Client->>BenzFactory: new BenzFactory()
BenzFactory-->>Client: 返回BenzFactory实例
%% 2. 客户端通过抽象工厂接口调用工厂方法
Client->>CarFactory: createCar()(多态调用BenzFactory的实现)
BenzFactory->>Benz: new Benz()(具体工厂创建具体产品)
Benz-->>BenzFactory: 返回Benz实例
BenzFactory-->>Car: 返回Benz实例(向上转型为Car)
Car-->>Client: 返回Car类型的Benz实例
%% 3. 客户端通过抽象产品接口使用产品
Client->>Car: drive()(多态调用Benz的实现)
Benz->>Client: 执行奔驰车的drive():"Benz is driving..."
4. 优点
- 符合开闭原则:新增产品时,只需新增具体产品类和对应的具体工厂类,无需修改现有工厂和客户端代码(如新增奥迪车,只需添加
Audi和AudiFactory)。 - 降低耦合度:客户端仅依赖抽象产品(
Car)和抽象工厂(CarFactory),不直接依赖具体产品和工厂,符合 “依赖倒置原则”。 - 封装产品创建细节:客户端无需知道具体产品的类名(如
Benz),只需通过工厂获取产品,简化客户端逻辑。 - 支持多态创建:不同具体工厂可创建不同产品,客户端通过切换工厂实现产品的动态替换(如从
BenzFactory切换到BMWFactory)。
5. 缺点
- 类数量增加:每个具体产品对应一个具体工厂,产品种类增多时,类数量会成对增加(如 n 个产品对应 n 个工厂),增加系统复杂度。
- 客户端需了解工厂类型:客户端需知道哪个具体工厂对应哪种产品(如 “要奔驰车需用
BenzFactory”),否则无法正确获取所需产品。 - 抽象层次提高:相比简单工厂模式,引入了更多抽象(抽象产品、抽象工厂),对新手而言理解难度略高。
三、Java 代码实现(汽车生产示例)
1. 抽象产品(Car)
定义所有汽车的共同接口:
// 抽象产品:汽车接口
public interface Car {
// 汽车行驶方法
void drive();
}
2. 具体产品(Benz、BMW)
实现抽象产品,提供具体功能:
// 具体产品1:奔驰车
public class Benz implements Car {
@Override
public void drive() {
System.out.println("奔驰车:平稳行驶中...");
}
}
// 具体产品2:宝马车
public class BMW implements Car {
@Override
public void drive() {
System.out.println("宝马车:激情驾驶中...");
}
}
3. 抽象工厂(CarFactory)
声明工厂方法,定义创建产品的接口:
// 抽象工厂:汽车工厂接口
public interface CarFactory {
// 工厂方法:创建汽车(返回抽象产品类型)
Car createCar();
}
4. 具体工厂(BenzFactory、BMWFactory)
实现工厂方法,创建具体产品:
// 具体工厂1:奔驰工厂
public class BenzFactory implements CarFactory {
@Override
public Car createCar() {
// 可在此添加奔驰车的创建细节(如配置、质检)
return new Benz();
}
}
// 具体工厂2:宝马工厂
public class BMWFactory implements CarFactory {
@Override
public Car createCar() {
// 可在此添加宝马车的创建细节
return new BMW();
}
}
5. 客户端(Client)
通过抽象工厂和抽象产品使用系统,无需依赖具体类:
// 客户端:使用汽车工厂
public class Client {
public static void main(String[] args) {
// 1. 选择具体工厂(可动态切换,如从配置文件读取)
CarFactory factory = new BenzFactory(); // 奔驰工厂
// CarFactory factory = new BMWFactory(); // 切换为宝马工厂
// 2. 通过工厂方法获取产品(返回抽象产品类型)
Car car = factory.createCar();
// 3. 使用产品(通过抽象接口调用)
car.drive();
}
}
6. 输出结果(使用 BenzFactory 时)
奔驰车:平稳行驶中...
若切换为BMWFactory,输出结果为:
宝马车:激情驾驶中...
7. 新增产品(奥迪车)的扩展示例
无需修改现有代码,只需新增具体产品和工厂:
// 新增具体产品:奥迪车
public class Audi implements Car {
@Override
public void drive() {
System.out.println("奥迪车:科技驾驶中...");
}
}
// 新增具体工厂:奥迪工厂
public class AudiFactory implements CarFactory {
@Override
public Car createCar() {
return new Audi();
}
}
// 客户端使用新工厂
public class Client {
public static void main(String[] args) {
CarFactory factory = new AudiFactory(); // 新增工厂
Car car = factory.createCar();
car.drive(); // 输出:奥迪车:科技驾驶中...
}
}
四、适用环境
工厂方法模式适用于以下场景,核心判断标准是 “产品种类可能扩展,且需将创建与使用分离”:
- 产品种类不确定,可能扩展:如日志系统(可能新增文件日志、数据库日志)、支付系统(可能新增支付宝、微信支付),新增产品时需避免修改现有代码。
- 客户端不依赖具体产品的创建细节:客户端只需知道 “获取产品”,无需知道产品的类名、初始化参数等(如 “我要支付”,无需知道支付接口的具体实现)。
- 需要通过子类决定创建哪种产品:父类无法预测需要创建的具体产品(如框架设计中,框架只定义接口,由用户实现具体产品和工厂)。
- 需封装产品创建过程:产品创建逻辑复杂(如需配置、初始化、校验),需将这些逻辑集中到工厂中,避免客户端代码混乱。
五、模式分析
1. 核心本质
工厂方法模式的本质是 “延迟实例化 + 抽象接口 + 子类实现”:
- 延迟实例化:将产品的创建延迟到具体工厂子类,父类(抽象工厂)不参与具体创建逻辑。
- 抽象接口:通过抽象产品和抽象工厂定义接口,确保客户端和工厂、产品之间的依赖是抽象而非具体。
- 子类实现:具体工厂子类负责创建对应的具体产品,每个产品与工厂一一对应,实现 “单一职责”。
2. 与其他模式的区别
| 模式 | 核心差异 | 典型场景 |
|---|---|---|
| 工厂方法模式 | 抽象工厂定义接口,具体工厂子类创建对应产品,支持扩展(符合开闭) | 汽车生产、日志系统(多产品类型) |
| 简单工厂模式 | 一个工厂类负责所有产品的创建,新增产品需修改工厂(违反开闭) | 产品类型少且稳定(如计算器) |
| 抽象工厂模式 | 一个工厂创建多个相关产品(产品族),如 “宝马工厂” 生产宝马车和宝马配件 | 产品族场景(如不同品牌的全套产品) |
| 建造者模式 | 关注产品的创建过程(分步构建复杂对象),如 “汽车建造者” 分步组装零件 | 复杂对象的分步构建(如电脑、文档) |
3. 关键设计原则
- 依赖倒置原则:客户端依赖抽象产品和抽象工厂,不依赖具体类(如
Client只依赖Car和CarFactory)。 - 开闭原则:新增产品时,只需新增具体产品和工厂,无需修改现有代码(如新增
Audi和AudiFactory)。 - 单一职责原则:每个具体工厂只负责创建一种具体产品(如
BenzFactory只创建Benz),逻辑清晰。
六、模式扩展
工厂方法模式可根据场景需求扩展出以下变体:
1. 带默认实现的抽象工厂
抽象工厂提供默认工厂方法实现,具体工厂可选择性重写(适用于大部分产品创建逻辑相似的场景):
// 带默认实现的抽象工厂
public abstract class AbstractCarFactory implements CarFactory {
// 默认实现:创建基础款汽车
@Override
public Car createCar() {
return new BasicCar(); // 基础款汽车
}
// 可选:抽象方法,强制子类实现特定产品
public abstract Car createPremiumCar(); // 高端款汽车
}
// 具体工厂可复用默认实现,或重写
public class BenzFactory extends AbstractCarFactory {
@Override
public Car createPremiumCar() {
return new BenzPremium(); // 奔驰高端款
}
// 复用默认的createCar(),返回基础款
}
2. 工厂方法返回缓存对象
工厂方法不每次创建新对象,而是返回缓存的实例(适用于单例产品或池化对象):
public class SingletonCarFactory implements CarFactory {
private static Car singletonCar; // 缓存单例对象
@Override
public synchronized Car createCar() {
if (singletonCar == null) {
singletonCar = new Benz(); // 仅首次创建
}
return singletonCar; // 返回缓存对象
}
}
3. 参数化工厂方法
抽象工厂的工厂方法接收参数,具体工厂根据参数返回不同产品(平衡工厂数量和灵活性):
// 参数化抽象工厂
public interface CarFactory {
// 工厂方法接收参数(如车型)
Car createCar(String model);
}
// 具体工厂根据参数创建不同产品
public class LuxuryCarFactory implements CarFactory {
@Override
public Car createCar(String model) {
switch (model) {
case "BenzS": return new BenzS();
case "BMWM5": return new BMWM5();
default: throw new IllegalArgumentException("未知车型");
}
}
}
4. 静态工厂方法(非模式标准,但广泛使用)
将工厂方法定义为静态方法(无需创建工厂实例),简化调用(如 Java 的Integer.valueOf()):
public class CarStaticFactory {
// 静态工厂方法:创建奔驰
public static Car createBenz() {
return new Benz();
}
// 静态工厂方法:创建宝马
public static Car createBMW() {
return new BMW();
}
}
// 客户端调用(无需创建工厂实例)
Car benz = CarStaticFactory.createBenz();
七、模式应用(通用 + Android)
1. 通用领域应用
Java 集合框架:
Collection.iterator()是工厂方法,ArrayList、HashSet等具体集合类(具体工厂)实现该方法,返回对应的Iterator(具体产品)。List<String> list = new ArrayList<>(); Iterator<String> iterator = list.iterator(); // 工厂方法:ArrayList创建对应的迭代器日志框架(SLF4J):
LoggerFactory.getLogger()是工厂方法,不同日志实现(如 Logback、Log4j)对应不同的具体工厂,返回适配的日志对象。Spring 框架:
FactoryBean接口是工厂方法模式的应用,getObject()方法由具体实现类(如JdbcTemplateFactoryBean)重写,创建并返回特定 Bean。数据库访问(JDBC):
DriverManager.getConnection()根据连接字符串选择对应的数据库驱动(具体工厂),创建数据库连接(具体产品)。
2. Android 中的应用
Android 框架和常用库大量使用工厂方法模式,核心场景集中在对象创建和框架扩展:
(1)BitmapFactory(核心应用)
角色对应:
- 抽象产品:
Bitmap(图片对象); - 具体产品:不同来源的
Bitmap(资源文件、文件、字节流等); - 抽象工厂:
BitmapFactory(包含静态工厂方法); - 具体工厂:
BitmapFactory的静态方法(decodeResource()、decodeFile()等)作为工厂方法,创建不同来源的Bitmap。
- 抽象产品:
核心逻辑:
// 客户端通过静态工厂方法创建Bitmap(不同来源) Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.image); // 从资源创建 Bitmap bitmap2 = BitmapFactory.decodeFile("/sdcard/image.jpg"); // 从文件创建 // 工厂方法隐藏了不同来源Bitmap的创建细节
(2)LayoutInflater(布局加载器)
角色对应:
- 抽象产品:
View(视图对象); - 具体产品:
TextView、Button等具体视图; - 抽象工厂:
LayoutInflater(声明inflate()工厂方法); - 具体工厂:
LayoutInflater的实现类(如PhoneLayoutInflater),重写inflate()创建具体视图。
- 抽象产品:
核心逻辑:
// 客户端通过工厂方法加载布局(创建View树) LayoutInflater inflater = LayoutInflater.from(context); View view = inflater.inflate(R.layout.activity_main, null); // 工厂方法创建View
(3)ViewModelProvider.Factory(ViewModel 创建)
角色对应:
- 抽象产品:
ViewModel(页面数据模型); - 具体产品:自定义
UserViewModel、OrderViewModel等; - 抽象工厂:
ViewModelProvider.Factory(声明create()工厂方法); - 具体工厂:
ViewModelProvider.NewInstanceFactory(默认工厂)或自定义工厂,创建具体ViewModel。
- 抽象产品:
核心逻辑:
// 自定义具体工厂:创建UserViewModel public class UserViewModelFactory implements ViewModelProvider.Factory { @Override public <T extends ViewModel> T create(Class<T> modelClass) { if (modelClass.isAssignableFrom(UserViewModel.class)) { return (T) new UserViewModel(); // 创建具体产品 } throw new IllegalArgumentException("未知ViewModel类型"); } } // 客户端使用工厂创建ViewModel ViewModelProvider provider = new ViewModelProvider(this, new UserViewModelFactory()); UserViewModel viewModel = provider.get(UserViewModel.class);
(4)IntentService(服务创建)
- 角色对应:
- 抽象产品:
Service(Android 服务); - 具体产品:自定义
DownloadService、SyncService等; - 抽象工厂:
IntentService(声明onHandleIntent()抽象方法,类似工厂方法); - 具体工厂:自定义
IntentService子类,重写onHandleIntent()实现具体服务逻辑。
- 抽象产品:
八、总结
工厂方法模式是 “对象创建” 的核心解决方案,其核心价值在于 “延迟创建 + 灵活扩展 + 解耦封装”:
- 核心优势:完美符合 “开闭原则”,新增产品无需修改现有代码;客户端与具体产品解耦,仅依赖抽象;封装了产品创建细节,简化客户端使用。
- 适用场景:产品种类可能扩展、需分离创建与使用、需封装创建逻辑的场景(如框架设计、多产品系统)。
- 实践建议:
- 简单场景(产品少且稳定)可用简单工厂,复杂场景(产品多变)用工厂方法;
- 抽象工厂和抽象产品尽量设计为接口,确保灵活性;
- 避免过度设计:若产品种类极少且不可能扩展,直接
new对象可能比引入工厂更简单; - 可结合依赖注入(如 Spring)管理具体工厂,实现工厂的动态切换。
工厂方法模式不仅是一种创建对象的技巧,更是一种 “面向抽象” 的设计思维 —— 通过抽象定义接口,由具体实现完成细节,使系统在变化中保持稳定,是构建可扩展框架和大型系统的重要工具。