当前位置: 首页 > news >正文

设计模式(二)创建型:工厂方法模式详解

设计模式(二)创建型:工厂方法模式详解

工厂方法模式(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 类图:

implements
implements
implements
implements
creates
creates
returns
«interface»
Product
+operation()
ConcreteProductA
+operation()
ConcreteProductB
+operation()
«abstract»
Creator
+someOperation()
+factoryMethod()
ConcreteCreatorA
+factoryMethod()
ConcreteCreatorB
+factoryMethod()

图解说明

  • Product 是抽象产品接口,定义了所有产品共有的行为。
  • ConcreteProductAConcreteProductB 是具体产品类,分别实现 Product 接口。
  • Creator 是抽象创建者类,包含一个抽象的 factoryMethod() 方法,用于返回 Product 对象;同时包含 someOperation() 方法,该方法内部调用 factoryMethod() 获取产品并使用其功能。
  • ConcreteCreatorAConcreteCreatorB 是具体创建者,分别重写 factoryMethod() 以返回 ConcreteProductAConcreteProductB 的实例。
  • 客户端代码通过 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 上运行时,则使用 MacDialogMacButton
  • 客户端 runBusinessLogic() 方法完全不关心具体产品类型,仅依赖抽象 DialogButton 接口,实现了创建与使用的解耦。

四、总结

工厂方法模式通过引入“工厂方法”这一间接层,成功实现了以下设计目标:

  • 解耦创建与使用:客户端不直接依赖具体产品类,仅依赖抽象接口。
  • 支持开闭原则:新增产品类型时无需修改现有代码,只需扩展新类。
  • 提升可测试性:可通过模拟(Mock)工厂返回测试对象,便于单元测试。
  • 促进模块化设计:将对象创建逻辑集中管理,避免散落在各处。

然而,该模式也带来一定复杂性:每新增一种产品,通常需要同时新增一个具体创建者类,可能导致类数量膨胀。因此,应在“灵活性需求”与“代码简洁性”之间权衡使用。

架构师洞见:
工厂方法模式是现代软件架构中“控制反转”(IoC)与“依赖注入”(DI)思想的雏形。在 Spring 等框架中,Bean 的创建虽不再显式使用工厂方法,但其背后仍是通过配置元数据(XML/注解)动态决定实例化哪个类,本质是工厂方法的集中化与配置化演进。架构师应认识到:工厂方法不仅是一种编码技巧,更是一种设计哲学——将“决策点”从代码中移出,交由更高层次的配置或运行时环境决定。未来,随着云原生与服务网格的发展,对象创建将进一步向运行时平台(如 Service Mesh、Serverless Runtime)转移,工厂方法的思想将以“声明式创建”、“自动注入”等形式持续演进。掌握其本质,才能在复杂系统中做出高内聚、低耦合的架构决策。

http://www.dtcms.com/a/301021.html

相关文章:

  • 设计模式(十一)结构型:外观模式详解
  • rename系统调用及示例
  • docker-desktop引擎启动失败报wsl --update
  • 推荐系统学习
  • QML视图组件:ListView、GridView、TableView、PathView
  • MyBatis Plus 乐观锁与悲观锁
  • 《C++ list 完全指南:list的模拟实现》
  • NodeJs接入腾讯云存储COS
  • MySQL 用户管理
  • 第六章 JavaScript 互操(3)JS调用.NET
  • Django5.1(131)—— 表单 API二(API参考)
  • 电科金仓 KingbaseES 深度解码:技术突破・行业实践・沙龙邀约 -- 融合数据库的变革之力
  • Java面试宝典:MySQL索引
  • 2-4、Dify案例实践—基于工作流构建商城用户评价智能分析系统
  • PyTorch武侠演义 第一卷:初入江湖 第7章:矿洞中的计算禁制
  • 基于mnn架构在本地 c++运行llm与mllm模型
  • 数据结构基本内容(第四篇:队列)
  • 2025.7.27
  • Java面试题及详细答案120道之(061-080)
  • C++算法竞赛篇(六)一维数组题型讲解
  • 【工具】python汇总发票(含源码)
  • Java排序算法之<希尔排序>
  • 7月27日星期日今日早报简报微语报早读
  • GitHub 趋势日报 (2025年07月25日)
  • Linux 系统网络配置及 IP 地址相关知识汇总
  • STM32 I2C通信完整教程:从协议原理到硬件实现
  • 一文快速了解Docker和命令详解
  • 模拟实现python的sklearn库中的Bunch类以及 load_iris 功能
  • 文件权限标记机制在知识安全共享中的应用实践
  • minio 对象存储