设计模式(二)创建型:工厂方法模式详解
设计模式(二)创建型:工厂方法模式详解
工厂方法模式(Factory Method Pattern)是 GoF 23 种设计模式中的经典创建型模式,其核心价值在于将对象的创建过程延迟到子类,从而实现创建逻辑与使用逻辑的解耦。它通过定义一个创建对象的接口,但由子类决定实例化哪一个具体类,有效解决了“硬编码依赖”问题,提升了系统的可扩展性与可维护性。该模式广泛应用于框架设计、插件系统、跨平台组件库、依赖注入容器等场景,是构建灵活、可插拔软件架构的重要基石。掌握工厂方法模式,是理解现代软件“控制反转”(IoC)思想的关键一步。
一、工厂方法模式详细介绍
工厂方法模式的核心思想是定义一个用于创建对象的接口,但让子类决定实例化哪一个具体类。它将对象的创建职责从客户端代码中剥离出来,交由一个专门的“工厂”来完成,从而避免在代码中直接使用 new
关键字创建具体类,降低耦合度。
该模式涉及四个关键角色:
- Product(产品接口):定义所有具体产品类的公共接口,客户端仅依赖此抽象接口。
- ConcreteProduct(具体产品类):实现 Product 接口的具体类,代表系统中实际被创建的对象。
- Creator(创建者抽象类或接口):声明工厂方法
factoryMethod()
,返回一个 Product 对象。Creator 可能还包含其他业务逻辑,这些逻辑会使用工厂方法返回的对象,但不关心其具体类型。 - ConcreteCreator(具体创建者):继承或实现 Creator,并重写工厂方法,返回一个具体的 ConcreteProduct 实例。
工厂方法模式的优势在于其开闭原则(Open-Closed Principle)的完美体现:当需要新增一种产品时,只需添加新的 ConcreteProduct 和对应的 ConcreteCreator,无需修改现有客户端或 Creator 的代码。这使得系统能够灵活应对需求变化,尤其适用于产品类型可能扩展的场景,如跨平台 UI 库(WindowsButton / MacButton)、数据库驱动(MySQLConnection / PostgreSQLConnection)等。
与简单工厂(Simple Factory)相比,工厂方法模式更符合面向对象设计原则,因为它不依赖条件判断来决定创建哪个类,而是通过继承和多态实现动态绑定,避免了“开关语句”带来的维护难题。
二、工厂方法模式的UML表示
以下是工厂方法模式的标准 UML 类图:
图解说明:
Product
是抽象产品接口,定义了所有产品共有的行为。ConcreteProductA
和ConcreteProductB
是具体产品类,分别实现Product
接口。Creator
是抽象创建者类,包含一个抽象的factoryMethod()
方法,用于返回Product
对象;同时包含someOperation()
方法,该方法内部调用factoryMethod()
获取产品并使用其功能。ConcreteCreatorA
和ConcreteCreatorB
是具体创建者,分别重写factoryMethod()
以返回ConcreteProductA
和ConcreteProductB
的实例。- 客户端代码通过
Creator
引用调用someOperation()
,实际创建和使用的产品类型由运行时的具体创建者决定,实现了多态创建。
三、一个简单的Java程序实例
以下是一个基于工厂方法模式的简单 Java 示例,模拟不同操作系统的按钮创建:
// 抽象产品接口
interface Button {void render();void onClick();
}// 具体产品类:Windows 按钮
class WindowsButton implements Button {public void render() {System.out.println("Rendering a Windows-style button.");}public void onClick() {System.out.println("Windows button clicked: Performing action...");}
}// 具体产品类:Mac 按钮
class MacButton implements Button {public void render() {System.out.println("Rendering a Mac-style button.");}public void onClick() {System.out.println("Mac button clicked: Triggering action...");}
}// 抽象创建者
abstract class Dialog {// 工厂方法:由子类实现public abstract Button createButton();// 业务逻辑:使用工厂方法创建的对象public void render() {Button button = createButton(); // 创建产品button.render(); // 使用产品button.onClick();}
}// 具体创建者:Windows 对话框
class WindowsDialog extends Dialog {@Overridepublic Button createButton() {return new WindowsButton();}
}// 具体创建者:Mac 对话框
class MacDialog extends Dialog {@Overridepublic Button createButton() {return new MacButton();}
}// 客户端代码
public class FactoryMethodDemo {private static Dialog dialog;// 根据环境配置决定使用哪个具体创建者static void configure() {if (System.getProperty("os.name").toLowerCase().contains("win")) {dialog = new WindowsDialog();} else {dialog = new MacDialog();}}static void runBusinessLogic() {dialog.render(); // 调用抽象方法,实际行为由具体创建者决定}public static void main(String[] args) {configure();runBusinessLogic();}
}
运行说明:
- 在 Windows 系统上运行时,
configure()
方法会创建WindowsDialog
实例,其createButton()
返回WindowsButton
,输出 Windows 风格的渲染和点击信息。 - 在 macOS 上运行时,则使用
MacDialog
和MacButton
。 - 客户端
runBusinessLogic()
方法完全不关心具体产品类型,仅依赖抽象Dialog
和Button
接口,实现了创建与使用的解耦。
四、总结
工厂方法模式通过引入“工厂方法”这一间接层,成功实现了以下设计目标:
- 解耦创建与使用:客户端不直接依赖具体产品类,仅依赖抽象接口。
- 支持开闭原则:新增产品类型时无需修改现有代码,只需扩展新类。
- 提升可测试性:可通过模拟(Mock)工厂返回测试对象,便于单元测试。
- 促进模块化设计:将对象创建逻辑集中管理,避免散落在各处。
然而,该模式也带来一定复杂性:每新增一种产品,通常需要同时新增一个具体创建者类,可能导致类数量膨胀。因此,应在“灵活性需求”与“代码简洁性”之间权衡使用。
架构师洞见:
工厂方法模式是现代软件架构中“控制反转”(IoC)与“依赖注入”(DI)思想的雏形。在 Spring 等框架中,Bean 的创建虽不再显式使用工厂方法,但其背后仍是通过配置元数据(XML/注解)动态决定实例化哪个类,本质是工厂方法的集中化与配置化演进。架构师应认识到:工厂方法不仅是一种编码技巧,更是一种设计哲学——将“决策点”从代码中移出,交由更高层次的配置或运行时环境决定。未来,随着云原生与服务网格的发展,对象创建将进一步向运行时平台(如 Service Mesh、Serverless Runtime)转移,工厂方法的思想将以“声明式创建”、“自动注入”等形式持续演进。掌握其本质,才能在复杂系统中做出高内聚、低耦合的架构决策。