设计模式:工厂方法模式(Factory Method Pattern)的原理、实现与典型应用场景
题目描述
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式让类的实例化推迟到子类进行。核心思想是:定义一个用于创建对象的接口(或抽象类),让子类决定实例化哪一个具体类。工厂方法模式也被称为“虚拟构造器(Virtual Constructor)”。
解题过程(循序渐进讲解)
步骤1:理解问题背景与动机
假设我们要设计一个跨平台的UI库,其中有一个Button组件。在不同操作系统(如Windows、macOS)下,按钮的渲染和行为可能不同。如果我们直接在代码中通过new WinButton()或new MacButton()来创建按钮,那么代码会与具体平台紧密耦合,难以扩展和维护。工厂方法模式通过引入“工厂”来封装对象的创建逻辑,将客户端代码与具体产品解耦。
步骤2:识别核心角色
工厂方法模式包含以下4个核心角色:
- 产品(Product):定义产品的接口(或抽象类)。
- 具体产品(Concrete Product):实现产品接口的具体类。
- 创建者/工厂(Creator):声明工厂方法(返回产品类型),也可以包含产品的一些默认操作。
- 具体创建者/具体工厂(Concrete Creator):重写工厂方法,返回具体产品的实例。
步骤3:用代码示例逐步实现
以下以跨平台按钮为例,展示工厂方法模式的实现:
-
定义产品接口
这是所有按钮的抽象,声明了按钮的通用方法(如render和onClick)。// 产品接口 public interface Button { void render(); void onClick(); } -
实现具体产品
针对不同平台实现具体的按钮类。// 具体产品:Windows按钮 public class WinButton implements Button { @Override public void render() { System.out.println("渲染一个Windows风格的按钮"); } @Override public void onClick() { System.out.println("Windows按钮被点击"); } } // 具体产品:macOS按钮 public class MacButton implements Button { @Override public void render() { System.out.println("渲染一个macOS风格的按钮"); } @Override public void onClick() { System.out.println("macOS按钮被点击"); } } -
定义创建者(抽象工厂)
创建者声明了工厂方法(createButton),该方法返回一个Button对象。创建者也可以包含一些与产品相关的业务逻辑(如renderButton)。// 创建者(抽象工厂) public abstract class Dialog { // 工厂方法:由子类实现,决定创建哪种按钮 public abstract Button createButton(); // 业务逻辑:使用工厂方法创建的产品 public void renderButton() { Button button = createButton(); // 调用工厂方法 button.render(); button.onClick(); } }注意:工厂方法是抽象的,延迟到子类实现。
-
实现具体创建者
每个具体创建者负责创建一种特定类型的按钮。// 具体创建者:Windows对话框 public class WinDialog extends Dialog { @Override public Button createButton() { return new WinButton(); // 返回Windows按钮 } } // 具体创建者:macOS对话框 public class MacDialog extends Dialog { @Override public Button createButton() { return new MacButton(); // 返回macOS按钮 } } -
客户端使用
客户端代码只依赖抽象的Dialog和Button,不依赖具体类。具体工厂和产品的选择可以在运行时决定(例如根据配置或环境)。public class Client { public static void main(String[] args) { Dialog dialog; // 模拟根据配置选择平台 String config = System.getProperty("os.name").toLowerCase(); if (config.contains("win")) { dialog = new WinDialog(); } else { dialog = new MacDialog(); } // 使用工厂方法创建产品并执行业务逻辑 dialog.renderButton(); } }运行结果(假设在Windows环境下):
渲染一个Windows风格的按钮 Windows按钮被点击
步骤4:分析模式特点与优势
-
优点:
- 解耦:将对象创建与使用分离,客户端只依赖抽象接口,符合“依赖倒置原则”。
- 可扩展性:添加新产品时,只需新增具体产品和具体工厂,无需修改现有代码(符合“开闭原则”)。
- 单一职责:每个具体工厂只负责创建一种产品,逻辑清晰。
-
缺点:
- 类数量增加:每新增一个产品,就需要新增一个具体工厂类,可能导致系统类数量膨胀。
- 增加复杂度:引入了额外的抽象层,对于简单对象创建可能显得繁琐。
步骤5:典型应用场景
- 跨平台UI库(如上述例子)。
- 日志记录器:不同日志输出方式(文件、控制台、数据库)对应不同的具体产品,由具体工厂创建。
- 数据库连接:针对不同数据库(MySQL、PostgreSQL)创建不同的连接对象。
- 框架设计:框架定义抽象产品,由应用程序提供具体实现(例如Spring中的
BeanFactory)。 - 文档处理:支持多种格式(PDF、Word)的文档处理器,每种格式由具体工厂创建。
步骤6:对比简单工厂模式
简单工厂模式(静态工厂)由一个工厂类通过条件判断来创建不同产品。它不符合开闭原则(新增产品需修改工厂类代码),而工厂方法模式通过多态将创建逻辑分散到各个具体工厂中,更符合设计原则。
总结
工厂方法模式通过将对象创建延迟到子类,实现了创建逻辑的封装与扩展。它是许多框架和库的基础模式,理解其核心思想有助于设计出灵活、可维护的系统。在实际面试中,面试官可能会要求手写代码实现,或结合其他模式(如抽象工厂模式)进行讨论。