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

发布于:2025-07-30 ⋅ 阅读:(22) ⋅ 点赞:(0)

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

工厂方法模式(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 {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
}

// 具体创建者:Mac 对话框
class MacDialog extends Dialog {
    @Override
    public 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)转移,工厂方法的思想将以“声明式创建”、“自动注入”等形式持续演进。掌握其本质,才能在复杂系统中做出高内聚、低耦合的架构决策。


网站公告

今日签到

点亮在社区的每一天
去签到