工厂方法模式(Factory Method Pattern)是创建型设计模式之一,通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而将对象的创建工作延迟到子类中。
也就是说,工厂方法设计模式通过定义一个工厂方法来让子类决定实例化哪一个类。
一、定义(Definition)
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类。工厂方法让类把实例化推迟到子类。
二、结构(UML 类图)
┌────────────────────┐
│ Product │<────────────┐
└────────────────────┘ │
▲ │
┌────────────────────┐ │
│ ConcreteProductA │ │
└────────────────────┘ │
┌────────────────────┐ │
│ ConcreteProductB │ │
└────────────────────┘ │
│
┌────────────────────┐ │
│ Creator │ │
│ + factoryMethod() │─────────────┘
└────────────────────┘
▲
┌────────────────────┐
│ ConcreteCreatorA │
└────────────────────┘
┌────────────────────┐
│ ConcreteCreatorB │
└────────────────────┘
三、核心角色
角色 | 职责说明 |
Product | 抽象产品,定义产品的共同接口 |
ConcreteProductA | 具体产品,实现 Product 接口 |
Creator | 抽象工厂,声明工厂方法 |
ConcreteCreatorA | 具体工厂,实现工厂方法,返回对应的产品对象 |
四、示例代码(Java)
场景说明:
假设我们有一个不同类型的 文档生成系统,系统可以生成不同类型的文档,如 PDF文档 和 Word文档。
我们使用工厂方法模式来根据需要生成不同类型的文档。
1. 抽象产品
/**
* @Date: 2024/12/26
* 1. 抽象产品(Product)
* 定义一个 Document 接口,表示所有文档类型。
*/
public interface Document {
void create();
}
2. 具体产品
/**
* @Date: 2024/12/26
*/
// PDF文档 具体产品(ConcreteProduct)
public class PdfDocument implements Document {
@Override
public void create() {
System.out.println("创建PDF文档");
}
}
/**
* @Date: 2024/12/26
*/
// Word文档 具体产品(ConcreteProduct)
public class WordDocument implements Document {
@Override
public void create() {
System.out.println("创建Word文档");
}
}
3. 抽象工厂
/**
* @Date: 2024/12/26
* 3. 抽象工厂(Creator)
* 它声明一个工厂方法 createDocument(),用于创建 Document 对象。
*/
public abstract class DocumentFactory {
public abstract Document createDocument();
}
4. 具体工厂
/**
* @Date: 2024/12/26
* 4. 具体工厂(ConcreteCreator)
*/
// PDF文档工厂
public class PdfDocumentFactory extends DocumentFactory {
@Override
public Document createDocument() {
return new PdfDocument();
}
}
/**
* @Date: 2024/12/26
* 4. 具体工厂(ConcreteCreator)
*/
// Word文档工厂
public class WordDocumentFactory extends DocumentFactory {
@Override
public Document createDocument() {
return new WordDocument();
}
}
5. 客户端代码
/**
* @Date: 2024/12/26
*/
public class Client {
public static void main(String[] args) {
// 创建PDF文档工厂
DocumentFactory pdfFactory = new PdfDocumentFactory();
Document pdfDocument = pdfFactory.createDocument();
pdfDocument.create(); // 输出: 创建PDF文档
// 创建Word文档工厂
DocumentFactory wordFactory = new WordDocumentFactory();
Document wordDocument = wordFactory.createDocument();
wordDocument.create(); // 输出: 创建Word文档
}
}
五、优缺点
✅ 优点
- 符合开闭原则:新增产品只需增加对应的工厂类,无需修改已有代码。
- 解耦创建者与具体产品:客户端只依赖抽象,不依赖具体类。
- 可替代简单工厂,更灵活。
❌ 缺点
- 每增加一个产品类,就需要增加一个新的工厂类,类数量增多。
- 增加系统复杂度。
六、适用场景
- 系统不应依赖产品类实例如何被创建、组合和表达。
- 一个类希望将它所创建的对象的职责委托给子类,并且你希望局部化这种对象的创建。
- 客户端需要创建的对象是某个抽象类或接口的子类,但不确定具体是哪一个。
七、现实例子类比
- 汽车工厂:不同汽车品牌(如 ToyotaFactory、BMWFactory)各自负责生产自己的车型(Product)。
- GUI 框架:WindowsButtonFactory 和 MacButtonFactory 分别创建不同平台风格的按钮。
八、与其他模式对比
模式 | 特点 |
简单工厂 | 一个工厂类生产多种产品,不符合开闭原则 |
工厂方法 | 一个工厂类生产一种产品,符合开闭原则 |
抽象工厂 | 一组相关产品对象的创建(比如一套UI组件) |
原型模式 | 通过克隆已有对象创建新对象,关注“复制”而非“创建” |
九、总结一句话:
工厂方法模式是“一个工厂对应一种产品”的对象创建模式,它通过抽象工厂方法让子类决定如何实例化,实现了“创建逻辑的延迟绑定” 和 “对扩展开放,对修改关闭” 的设计目标。