工厂模式
工厂模式提供了一种创建对象的最佳方式,将对象的创建和使用分离。
一、三种工厂模式
简单工厂 ──→ 工厂方法 ──→ 抽象工厂
(简单) (中等) (复杂)| 模式 | 特点 | 适用场景 |
|---|---|---|
| 简单工厂 | 一个工厂创建所有产品 | 产品种类少且固定 |
| 工厂方法 | 每个产品一个工厂 | 产品种类可能增加 |
| 抽象工厂 | 创建产品族 | 多个产品族 |
二、简单工厂
1. 结构
┌─────────────┐ ┌─────────────┐
│ Product │◄────│ ConcreteProduct │
│ (抽象产品) │ │ (具体产品) │
└─────────────┘ └─────────────┘
▲
│ 创建
┌───────┴───────┐
│ SimpleFactory │
│ (简单工厂) │
└───────────────┘2. 实现
// 抽象产品
public interface Product {
void use();
}
// 具体产品A
public class ProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
public class ProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 简单工厂
public class SimpleFactory {
public static Product create(String type) {
switch (type) {
case "A":
return new ProductA();
case "B":
return new ProductB();
default:
throw new IllegalArgumentException("未知产品类型: " + type);
}
}
}
// 使用
Product product = SimpleFactory.create("A");
product.use();3. 优缺点
优点:
- 客户端不需要知道具体产品类名
- 集中管理对象创建
缺点:
- 违背开闭原则(新增产品需修改工厂)
- 工厂类职责过重
三、工厂方法
1. 结构
┌─────────────┐ ┌─────────────┐
│ Product │◄────│ ProductA │
└─────────────┘ └─────────────┘
▲ ▲
│ │ 创建
┌───────┴───────┐ ┌─────┴──────┐
│ Factory │◄──│ FactoryA │
│ (抽象工厂) │ │ (具体工厂) │
└───────────────┘ └────────────┘2. 实现
// 抽象产品
public interface Product {
void use();
}
// 具体产品
public class ProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
public class ProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 抽象工厂
public interface Factory {
Product create();
}
// 具体工厂
public class FactoryA implements Factory {
@Override
public Product create() {
return new ProductA();
}
}
public class FactoryB implements Factory {
@Override
public Product create() {
return new ProductB();
}
}
// 使用
Factory factory = new FactoryA();
Product product = factory.create();
product.use();3. 优缺点
优点:
- 符合开闭原则(新增产品只需新增工厂)
- 符合单一职责原则
- 客户端无需知道具体产品类
缺点:
- 类数量增加
- 增加系统抽象性
四、抽象工厂
1. 结构
产品族:
┌──────────────┐ ┌──────────────┐
│ 产品A系列 │ │ 产品B系列 │
│ ┌──────────┐ │ │ ┌──────────┐ │
│ │ProductA1 │ │ │ │ProductB1 │ │
│ └──────────┘ │ │ └──────────┘ │
│ ┌──────────┐ │ │ ┌──────────┐ │
│ │ProductA2 │ │ │ │ProductB2 │ │
│ └──────────┘ │ │ └──────────┘ │
└──────────────┘ └──────────────┘
▲ ▲
│ │
┌───────┴─────────────────┴───────┐
│ AbstractFactory │
│ + createProduct1() │
│ + createProduct2() │
└─────────────────────────────────┘2. 实现
// 抽象产品1
public interface Button {
void click();
}
// 抽象产品2
public interface TextBox {
void input();
}
// Windows 产品族
public class WindowsButton implements Button {
@Override
public void click() {
System.out.println("Windows 按钮");
}
}
public class WindowsTextBox implements TextBox {
@Override
public void input() {
System.out.println("Windows 文本框");
}
}
// Mac 产品族
public class MacButton implements Button {
@Override
public void click() {
System.out.println("Mac 按钮");
}
}
public class MacTextBox implements TextBox {
@Override
public void input() {
System.out.println("Mac 文本框");
}
}
// 抽象工厂
public interface GUIFactory {
Button createButton();
TextBox createTextBox();
}
// Windows 工厂
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextBox createTextBox() {
return new WindowsTextBox();
}
}
// Mac 工厂
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextBox createTextBox() {
return new MacTextBox();
}
}
// 使用
GUIFactory factory;
if (System.getProperty("os.name").contains("Windows")) {
factory = new WindowsFactory();
} else {
factory = new MacFactory();
}
Button button = factory.createButton();
TextBox textBox = factory.createTextBox();3. 优缺点
优点:
- 保证产品族的一致性
- 符合开闭原则(新增产品族)
- 客户端无需知道具体产品类
缺点:
- 新增产品类型困难(需修改所有工厂)
- 增加系统复杂度
五、实际应用
1. JDK 中的应用
java.util.Calendar:
Calendar cal = Calendar.getInstance();
// 根据时区和地区返回具体的 Calendar 实现java.util.Collections:
List<String> list = Collections.singletonList("hello");
// 工厂方法创建不可变集合2. Spring 中的应用
BeanFactory:
public interface BeanFactory {
Object getBean(String name);
<T> T getBean(Class<T> requiredType);
}3. 日志框架
// SLF4J
Logger logger = LoggerFactory.getLogger(MyClass.class);
// 根据绑定返回具体的 Logger 实现(Logback/Log4j2)六、模式对比
1. 简单工厂 vs 工厂方法
| 对比项 | 简单工厂 | 工厂方法 |
|---|---|---|
| 扩展性 | 差 | 好 |
| 类数量 | 少 | 多 |
| 复杂度 | 低 | 中 |
| 适用场景 | 产品固定 | 产品可扩展 |
2. 工厂方法 vs 抽象工厂
| 对比项 | 工厂方法 | 抽象工厂 |
|---|---|---|
| 产品维度 | 单一产品 | 产品族 |
| 扩展产品类型 | 容易 | 困难 |
| 扩展产品族 | 困难 | 容易 |
| 复杂度 | 中 | 高 |
七、面试高频问题
Q1: 工厂模式的核心思想是什么?
将对象的创建和使用分离,降低耦合度:
- 客户端不直接 new 对象
- 由工厂负责创建
- 客户端只关心接口
Q2: 什么时候用简单工厂 vs 工厂方法?
产品种类少且固定 → 简单工厂
产品种类可能增加 → 工厂方法Q3: 抽象工厂适合什么场景?
- 需要创建产品族
- 产品之间有关联关系
- 需要保证产品族一致性
Q4: 工厂模式与建造者模式的区别?
| 模式 | 关注点 | 适用场景 |
|---|---|---|
| 工厂模式 | 创建什么 | 创建不同类型的对象 |
| 建造者模式 | 怎么创建 | 创建复杂对象,关注构建过程 |
Q5: Spring 的 BeanFactory 是什么模式?
BeanFactory 使用了工厂方法模式:
getBean()方法创建 Bean- 不同的 ApplicationContext 是不同的工厂实现
- 支持 Bean 的生命周期管理
八、最佳实践
1. 选择合适模式
// 产品固定,使用简单工厂
Product product = SimpleFactory.create("A");
// 产品可扩展,使用工厂方法
Factory factory = new FactoryA();
Product product = factory.create();
// 产品族,使用抽象工厂
GUIFactory factory = new WindowsFactory();
Button button = factory.createButton();
TextBox textBox = factory.createTextBox();2. 配合配置使用
// 通过配置决定使用哪个工厂
String factoryType = config.get("factory.type");
Factory factory = FactoryProvider.getFactory(factoryType);3. 使用反射减少类数量
public class ReflectionFactory {
public static <T> T create(Class<T> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("创建实例失败", e);
}
}
}更新时间:2026年3月16日