抽象工厂模式
核心思想回顾:
抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象(一个产品族),而客户端代码无需指定这些对象的具体类。这使得客户端代码与具体产品的实现解耦,并且可以轻松地切换整个产品族。
场景想象:
假设你要开发一个跨平台的 UI 库,这个库需要在 Windows 和 macOS 上都能运行,并且提供各自平台原生观感的按钮和复选框。
产品族1 (Windows): Windows 风格的按钮,Windows 风格的复选框。
产品族2 (macOS): macOS 风格的按钮,macOS 风格的复选框。
你希望你的应用程序代码在创建这些 UI 元素时,不需要关心当前运行的是哪个操作系统,只需要告诉工厂“给我一个按钮”和“给我一个复选框”,工厂就能提供与当前平台匹配的组件。
模式的参与者 (Java 实现):
AbstractProduct (抽象产品):定义产品族中每种产品的接口。
Java: 通常是 interface。
例子:interface Button, interface Checkbox。
ConcreteProduct (具体产品):实现抽象产品接口,代表产品族中的具体产品。
Java: class 实现相应的 interface。
例子:class WindowsButton implements Button, class MacOSButton implements Button, class WindowsCheckbox implements Checkbox, class MacOSCheckbox implements Checkbox。
AbstractFactory (抽象工厂):声明一组用于创建抽象产品的方法。
Java: 通常是 interface。
例子:interface GUIFactory { Button createButton(); Checkbox createCheckbox(); }。
ConcreteFactory (具体工厂):实现抽象工厂接口,负责创建特定产品族中的具体产品。
Java: class 实现 GUIFactory 接口。
例子:class WindowsFactory implements GUIFactory, class MacOSFactory implements GUIFactory。
Client (客户端):仅使用 AbstractFactory 和 AbstractProduct 接口。
Java: 一个使用 GUIFactory 来创建 UI 组件的类。
例子:class Application。
Java 示例代码:
// 1. AbstractProduct (抽象产品接口) interface Button { void paint(); } interface Checkbox { void paint(); } // 2. ConcreteProduct (具体产品 - Windows 风格) class WindowsButton implements Button { @Override public void paint() { System.out.println("Rendering a Windows style button."); } } class WindowsCheckbox implements Checkbox { @Override public void paint() { System.out.println("Rendering a Windows style checkbox."); } } // 2. ConcreteProduct (具体产品 - macOS 风格) class MacOSButton implements Button { @Override public void paint() { System.out.println("Rendering a macOS style button."); } } class MacOSCheckbox implements Checkbox { @Override public void paint() { System.out.println("Rendering a macOS style checkbox."); } } // 3. AbstractFactory (抽象工厂接口) interface GUIFactory { Button createButton(); Checkbox createCheckbox(); } // 4. ConcreteFactory (具体工厂 - Windows 工厂) class WindowsFactory implements GUIFactory { @Override public Button createButton() { return new WindowsButton(); } @Override public Checkbox createCheckbox() { return new WindowsCheckbox(); } } // 4. ConcreteFactory (具体工厂 - macOS 工厂) class MacOSFactory implements GUIFactory { @Override public Button createButton() { return new MacOSButton(); } @Override public Checkbox createCheckbox() { return new MacOSCheckbox(); } } // 5. Client (客户端) class Application { private Button button; private Checkbox checkbox; private GUIFactory factory; public Application(GUIFactory factory) { this.factory = factory; } public void createUI() { // 客户端不关心具体是哪个工厂,也不关心具体的产品类型 // 它只知道从工厂获取 Button 和 Checkbox 的抽象 this.button = factory.createButton(); this.checkbox = factory.createCheckbox(); } public void paintUI() { if (button != null && checkbox != null) { button.paint(); checkbox.paint(); } else { System.out.println("UI components not created yet. Call createUI() first."); } } } // 主程序,用于演示 public class AbstractFactoryDemo { // 辅助方法,根据配置或环境决定使用哪个工厂 private static Application configureApplication() { GUIFactory factory; String osName = System.getProperty("os.name").toLowerCase(); if (osName.contains("win")) { factory = new WindowsFactory(); System.out.println("Configuring for Windows OS."); } else if (osName.contains("mac")) { factory = new MacOSFactory(); System.out.println("Configuring for macOS."); } else { // 默认或不支持的操作系统,可以抛出异常或使用默认工厂 System.out.println("OS not specifically supported, defaulting to Windows style."); factory = new WindowsFactory(); } return new Application(factory); } public static void main(String[] args) { // 根据当前环境配置应用程序 Application app = configureApplication(); app.createUI(); app.paintUI(); System.out.println("\n--- Manually switching to MacOS factory for demonstration ---"); // 强制使用 macOS 工厂进行演示 Application macApp = new Application(new MacOSFactory()); macApp.createUI(); macApp.paintUI(); System.out.println("\n--- Manually switching to Windows factory for demonstration ---"); // 强制使用 Windows 工厂进行演示 Application winApp = new Application(new WindowsFactory()); winApp.createUI(); winApp.paintUI(); } }
代码解释:
Button 和 Checkbox 是抽象产品接口。
WindowsButton, WindowsCheckbox, MacOSButton, MacOSCheckbox 是具体产品实现。
GUIFactory 是抽象工厂接口,它声明了创建 Button 和 Checkbox 的方法。
WindowsFactory 和 MacOSFactory 是具体工厂,它们分别实现了 GUIFactory,用于创建对应平台的 UI 组件。
Application 是客户端。它的构造函数接收一个 GUIFactory。在 createUI() 方法中,它使用这个工厂来创建按钮和复选框,而不需要知道具体是哪个工厂或哪个产品。
AbstractFactoryDemo.configureApplication() 方法模拟了根据操作系统选择合适工厂的逻辑。
main 方法展示了如何使用这个模式。客户端 (Application) 的代码是通用的,只需要在初始化时传入不同的工厂实例,就能得到不同风格的 UI 组件。
优点:
隔离具体类:客户端代码与具体产品的创建逻辑解耦,只依赖于抽象接口。
易于交换产品族:改变应用程序使用的产品族非常容易,只需要更换具体工厂的实例即可。例如,从 WindowsFactory 切换到 MacOSFactory。
保证产品兼容性:因为一个具体工厂只创建属于同一个产品族的产品,所以可以保证客户端创建出来的产品是相互兼容的(例如,Windows 按钮和 Windows 复选框搭配)。
符合开闭原则(对扩展开放,对修改关闭):当需要支持一个新的产品族(比如 Linux GTK 风格)时,只需要添加新的具体产品类(GTKButton, GTKCheckbox)和新的具体工厂类(GTKFactory),而不需要修改现有的工厂接口或客户端代码。
缺点:
难以增加新的产品种类:如果要在抽象工厂接口中增加一个新的抽象产品(比如 createTextField()),那么所有的具体工厂类都需要修改以实现这个新方法。这违反了开闭原则。对于这种情况,可能需要考虑其他模式,或者对抽象工厂进行扩展。
何时使用:
当你的系统需要独立于其产品的创建、组合和表示方式时。
当你的系统需要配置多个产品系列中的一个时。
当你希望强制用户使用同一产品系列中的对象,以保证兼容性时。
当你提供一个产品库,并且只想暴露其接口,隐藏其具体实现时。
抽象工厂模式是处理复杂对象创建,特别是需要保证产品族一致性时的强大工具。