工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,用于创建对象而无需指定具体的类。它通过将对象的创建逻辑封装到工厂类中,提供一种灵活的方式来生成不同类型的对象。工厂模式在软件开发中广泛应用,特别是在需要根据条件动态创建对象时。以下是对工厂模式的详细介绍,包括定义、类型、实现方式、优缺点、应用场景和示例代码(以 Java 为例,但概念适用于多种语言)。
1. 定义
- 工厂模式:通过一个工厂类(或方法)来创建对象,而不是直接使用
new
关键字。工厂模式将对象的创建与使用分离,提高代码的灵活性和可维护性。 - 核心目标:
- 封装对象创建逻辑。
- 提供统一的接口来创建不同类型的对象。
- 支持扩展,符合开闭原则(对扩展开放,对修改关闭)。
- 关键特点:
- 工厂类负责创建对象。
- 客户端代码通过工厂接口获取对象,无需了解具体实现。
2. 工厂模式的类型
工厂模式有三种常见变体,每种适用于不同场景:
2.1 简单工厂模式(Simple Factory Pattern)
- 特点:一个工厂类根据参数创建不同类型的对象(不属于 GoF 的 23 种设计模式,但常作为工厂模式的入门)。
- 适用场景:对象类型较少,创建逻辑简单。
- 缺点:违反开闭原则,新增类型需修改工厂类代码。
2.2 工厂方法模式(Factory Method Pattern)
- 特点:定义一个创建对象的接口,让子类决定实例化哪个类。每个具体产品对应一个具体工厂。
- 适用场景:需要支持多种产品,且产品可能扩展。
- 优点:符合开闭原则,易于扩展。
2.3 抽象工厂模式(Abstract Factory Pattern)
- 特点:提供一个接口,用于创建一系列相关或依赖对象的家族,而无需指定具体类。
- 适用场景:需要创建一组相关对象(如 UI 组件的不同风格)。
- 优点:支持产品族的创建,保持一致性。
3. 实现方式
以下分别展示三种工厂模式的实现(以 Java 为例)。
3.1 简单工厂模式
创建一个工厂类,根据参数返回不同类型的对象。
// 产品接口
interface Product {
void use();
}
// 具体产品
class ConcreteProductA implements Product {
public void use() {
System.out.println("Using Product A");
}
}
class ConcreteProductB implements Product {
public void use() {
System.out.println("Using Product B");
}
}
// 简单工厂
class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
}
return null;
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
productA.use(); // 输出: Using Product A
Product productB = SimpleFactory.createProduct("B");
productB.use(); // 输出: Using Product B
}
}
- 说明:
SimpleFactory
根据参数type
创建不同产品。- 缺点:新增产品类型需修改
createProduct
方法。
3.2 工厂方法模式
为每个产品定义一个具体工厂,工厂类与产品类一一对应。
// 产品接口
interface Product {
void use();
}
// 具体产品
class ConcreteProductA implements Product {
public void use() {
System.out.println("Using Product A");
}
}
class ConcreteProductB implements Product {
public void use() {
System.out.println("Using Product B");
}
}
// 工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂
class ConcreteFactoryA implements Factory {
public Product createProduct() {
return new ConcreteProductA();
}
}
class ConcreteFactoryB implements Factory {
public Product createProduct() {
return new ConcreteProductB();
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.use(); // 输出: Using Product A
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.use(); // 输出: Using Product B
}
}
- 说明:
- 每个产品有对应的工厂类,新增产品只需添加新工厂和新产品类。
- 符合开闭原则,扩展性更好。
3.3 抽象工厂模式
创建一组相关的产品(如按钮和文本框的 UI 组件)。
// 抽象产品接口
interface Button {
void render();
}
interface TextField {
void display();
}
// 具体产品 - Windows 风格
class WindowsButton implements Button {
public void render() {
System.out.println("Rendering Windows Button");
}
}
class WindowsTextField implements TextField {
public void display() {
System.out.println("Displaying Windows TextField");
}
}
// 具体产品 - Mac 风格
class MacButton implements Button {
public void render() {
System.out.println("Rendering Mac Button");
}
}
class MacTextField implements TextField {
public void display() {
System.out.println("Displaying Mac TextField");
}
}
// 抽象工厂接口
interface UIFactory {
Button createButton();
TextField createTextField();
}
// 具体工厂
class WindowsFactory implements UIFactory {
public Button createButton() {
return new WindowsButton();
}
public TextField createTextField() {
return new WindowsTextField();
}
}
class MacFactory implements UIFactory {
public Button createButton() {
return new MacButton();
}
public TextField createTextField() {
return new MacTextField();
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
UIFactory windowsFactory = new WindowsFactory();
Button winButton = windowsFactory.createButton();
TextField winTextField = windowsFactory.createTextField();
winButton.render(); // 输出: Rendering Windows Button
winTextField.display(); // 输出: Displaying Windows TextField
UIFactory macFactory = new MacFactory();
Button macButton = macFactory.createButton();
TextField macTextField = macFactory.createTextField();
macButton.render(); // 输出: Rendering Mac Button
macTextField.display(); // 输出: Displaying Mac TextField
}
}
- 说明:
- 抽象工厂模式支持创建一组相关产品(如 Windows 或 Mac 的 UI 组件)。
- 客户端通过工厂接口创建一致的产品族。
4. 优缺点
优点
- 封装创建逻辑:客户端无需关心具体类的实例化过程。
- 提高灵活性:通过工厂接口可以动态选择创建的对象类型。
- 符合开闭原则(工厂方法和抽象工厂):新增产品无需修改现有代码。
- 一致性(抽象工厂):确保创建的产品族兼容。
缺点
- 代码复杂性:工厂方法和抽象工厂会引入额外的类,增加代码量。
- 简单工厂的局限:新增产品需修改工厂类,违反开闭原则。
- 维护成本:在大型系统中,管理多个工厂类可能较复杂。
5. 应用场景
- 动态创建对象:根据配置或条件创建不同类型的对象(如数据库驱动:MySQL、PostgreSQL)。
- UI 框架:创建不同风格的 UI 组件(如 Windows、Mac 风格)。
- 插件系统:动态加载不同插件或模块。
- 日志框架:创建不同类型的日志记录器(如文件日志、控制台日志)。
- 对象池管理:管理可重用的对象实例。
6. 与其他模式的对比
- 单例模式 vs 工厂模式:
- 单例模式:确保一个类只有一个实例。
- 工厂模式:关注创建不同类型的对象,实例数量不限。
- 工厂方法 vs 抽象工厂:
- 工厂方法:为单一产品类型提供创建接口。
- 抽象工厂:为产品族提供创建接口。
- 工厂模式 vs 建造者模式:
- 工厂模式:关注创建完整对象。
- 建造者模式:关注分步构建复杂对象。
7. 在其他语言中的实现
Objective-C 工厂方法
// Product.h
@protocol Product <NSObject>
- (void)use;
@end
// ConcreteProductA.h
@interface ConcreteProductA : NSObject <Product>
@end
// ConcreteProductA.m
@implementation ConcreteProductA
- (void)use {
NSLog(@"Using Product A");
}
@end
// ConcreteProductB.h
@interface ConcreteProductB : NSObject <Product>
@end
// ConcreteProductB.m
@implementation ConcreteProductB
- (void)use {
NSLog(@"Using Product B");
}
@end
// Factory.h
@protocol Factory <NSObject>
- (id<Product>)createProduct;
@end
// ConcreteFactoryA.h
@interface ConcreteFactoryA : NSObject <Factory>
@end
// ConcreteFactoryA.m
@implementation ConcreteFactoryA
- (id<Product>)createProduct {
return [[ConcreteProductA alloc] init];
}
@end
// 使用示例
int main(int argc, const char * argv[]) {
@autoreleasepool {
id<Factory> factory = [[ConcreteFactoryA alloc] init];
id<Product> product = [factory createProduct];
[product use]; // 输出: Using Product A
}
return 0;
}
JavaScript 简单工厂
class ProductA {
use() {
console.log("Using Product A");
}
}
class ProductB {
use() {
console.log("Using Product B");
}
}
class SimpleFactory {
static createProduct(type) {
if (type === "A") {
return new ProductA();
} else if (type === "B") {
return new ProductB();
}
return null;
}
}
// 使用
const productA = SimpleFactory.createProduct("A");
productA.use(); // 输出: Using Product A
8. 注意事项
- 选择合适的工厂模式:
- 简单工厂适合小型项目,逻辑简单。
- 工厂方法适合需要扩展的场景。
- 抽象工厂适合创建相关产品族。
- 性能考虑:工厂模式可能增加对象创建的间接层,注意性能开销。
- 框架支持:在现代框架(如 Spring)中,工厂模式常由 IoC 容器实现(如
BeanFactory
)。 - 测试性:工厂模式便于 Mock 测试,可以通过注入不同工厂模拟行为。
9. 总结
- 工厂模式通过封装对象创建逻辑,提高代码灵活性和可维护性。
- 三种变体:
- 简单工厂:简单但扩展性差。
- 工厂方法:符合开闭原则,适合单一产品扩展。
- 抽象工厂:适合创建相关产品族。
- 应用场景:动态对象创建、UI 组件、插件系统等。
- 推荐实践:优先选择工厂方法或抽象工厂,结合依赖注入框架使用。
如果你需要更详细的代码示例(特定语言或场景,如 iOS UIKit 工厂)、与其他模式的对比,或深入探讨某变体的实现,请告诉我!