通俗易懂设计模式(抽象工厂模式)

159 阅读6分钟

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式允许客户端使用抽象接口来创建一组相关的产品,而不需要知道具体的实现类。

抽象工厂模式的优点:

  1. 解耦:将对象的创建和使用分离,降低了系统的耦合度。
  2. 扩展性:增加新的产品族时,只需创建新的抽象工厂子类,不需要修改已有代码。
  3. 可维护性:抽象工厂模式使得代码更易于维护,因为产品族的创建逻辑被封装在抽象工厂子类中。

抽象工厂模式的缺点:

  1. 增加类的数量:由于需要为每个产品族创建一个抽象工厂子类,因此类的数量会增加。
  2. 增加系统的复杂度:抽象工厂模式增加了系统的复杂度,需要更多的代码来实现。

Java 实现抽象工厂模式的示例代码:

// 抽象产品类A
public interface ProductA {
    void show();
}

// 具体产品类A1
public class ProductA1 implements ProductA {
    @Override
    public void show() {
        System.out.println("Product A1");
    }
}

// 具体产品类A2
public class ProductA2 implements ProductA {
    @Override
    public void show() {
        System.out.println("Product A2");
    }
}

// 抽象产品类B
public interface ProductB {
    void show();
}

// 具体产品类B1
public class ProductB1 implements ProductB {
    @Override
    public void show() {
        System.out.println("Product B1");
    }
}

// 具体产品类B2
public class ProductB2 implements ProductB {
    @Override
    public void show() {
        System.out.println("Product B2");
    }
}

// 抽象工厂类
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂类1
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

// 具体工厂类2
public class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory = new ConcreteFactory1();
        ProductA productA = factory.createProductA();
        ProductB productB = factory.createProductB();
        productA.show();
        productB.show();
    }
}

在这个示例中,我们定义了两个抽象产品类 ProductAProductB,以及四个具体产品类 ProductA1ProductA2ProductB1ProductB2。接着,我们定义了一个抽象工厂类 AbstractFactory,它包含了创建两种产品的方法。然后,我们定义了两个具体工厂类 ConcreteFactory1ConcreteFactory2,它们分别实现了 createProductA()createProductB() 方法,用于创建对应的产品实例。

在客户端代码中,我们创建了一个具体工厂类 ConcreteFactory1 的实例,并通过调用 createProductA()createProductB() 方法创建了两个产品实例。然后,我们调用 show() 方法显示产品信息。

使用抽象工厂模式时,需要注意以下几点:

  1. 抽象工厂模式适用于创建一组相关的产品,且这些产品之间存在依赖关系。例如,一个图形界面库可能包含按钮、文本框等多种控件,这些控件之间存在依赖关系,可以使用抽象工厂模式来创建。
  2. 抽象工厂模式需要为每个产品族创建一个抽象工厂子类,因此类的数量会增加。在产品族较多的情况下,需要考虑减少类的数量,可以使用其他创建型设计模式,如工厂方法模式(Factory Method Pattern)。

场景举例

场景一:跨平台UI组件库

在开发跨平台的应用程序时,我们可能需要为不同的操作系统提供不同的UI组件。例如,对于Windows系统,我们可能需要使用WinForms或WPF;而对于macOS系统,我们可能需要使用Cocoa。为了实现跨平台的UI组件库,我们可以使用抽象工厂模式。

使用抽象工厂模式来实现跨平台UI组件库,可以让代码更加简洁、易于维护。具体实现如下:

// UI组件接口
interface UIComponent {
    void render();
}

// 按钮组件接口
interface Button extends UIComponent {
    void onClick();
}

// 文本框组件接口
interface TextField extends UIComponent {
    void setText(String text);
    String getText();
}

// Windows平台UI组件实现
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering Windows button");
    }

    @Override
    public void onClick() {
        System.out.println("Windows button clicked");
    }
}

class WindowsTextField implements TextField {
    @Override
    public void render() {
        System.out.println("Rendering Windows text field");
    }

    @Override
    public void setText(String text) {
        System.out.println("Setting Windows text field text to: " + text);
    }

    @Override
    public String getText() {
        return "Windows text field text";
    }
}

// macOS平台UI组件实现
class MacOSButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering macOS button");
    }

    @Override
    public void onClick() {
        System.out.println("macOS button clicked");
    }
}

class MacOSTextField implements TextField {
    @Override
    public void render() {
        System.out.println("Rendering macOS text field");
    }

    @Override
    public void setText(String text) {
        System.out.println("Setting macOS text field text to: " + text);
    }

    @Override
    public String getText() {
        return "macOS text field text";
    }
}

// UI组件工厂接口
interface UIComponentFactory {
    Button createButton();
    TextField createTextField();
}

// Windows平台UI组件工厂实现
class WindowsUIComponentFactory implements UIComponentFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextField createTextField() {
        return new WindowsTextField();
    }
}

// macOS平台UI组件工厂实现
class MacOSUIComponentFactory implements UIComponentFactory {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }

    @Override
    public TextField createTextField() {
        return new MacOSTextField();
    }
}

// 跨平台UI组件管理器
class UIManager {
    private UIComponentFactory factory;

    public UIManager(UIComponentFactory factory) {
        this.factory = factory;
    }

    public Button createButton() {
        return factory.createButton();
    }

    public TextField createTextField() {
        return factory.createTextField();
    }
}

// 测试类
public class AbstractFactoryPatternDemo {
    public static void main(String[] args) {
        // 根据当前操作系统选择合适的UI组件工厂
        UIComponentFactory factory;
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("windows")) {
            factory = new WindowsUIComponentFactory();
        } else if (os.contains("mac")) {
            factory = new MacOSUIComponentFactory();
        } else {
            throw new UnsupportedOperationException("Unsupported operating system");
        }

        UIManager uiManager = new UIManager(factory);
        Button button = uiManager.createButton();
        TextField textField = uiManager.createTextField();

        button.render();
        button.onClick();
        textField.render();
        textField.setText("Hello, World!");
        System.out.println(textField.getText());
    }
}

场景二:多种编程语言的日志记录器

在开发跨语言的应用程序时,我们可能需要为不同的编程语言提供不同的日志记录器。例如,对于Java,我们可能需要使用Log4j或SLF4J;而对于Python,我们可能需要使用logging模块。为了实现跨语言的日志记录器,我们可以使用抽象工厂模式。

使用抽象工厂模式来实现多种编程语言的日志记录器,可以让代码更加简洁、易于维护。具体实现如下:

// 日志记录器接口
interface Logger {
    void log(String message);
}

// Java日志记录器实现
class JavaLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("Logging message in Java: " + message);
    }
}

// Python日志记录器实现
class PythonLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("Logging message in Python: " + message);
    }
}

// 日志记录器工厂接口
interface LoggerFactory {
    Logger createLogger();
}

// Java日志记录器工厂实现
class JavaLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        return new JavaLogger();
    }
}

// Python日志记录器工厂实现
class PythonLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        return new PythonLogger();
    }
}

// 跨语言日志记录器管理器
class LogManager {
    private LoggerFactory factory;

    public LogManager(LoggerFactory factory) {
        this.factory = factory;
    }

    public Logger createLogger() {
        return factory.createLogger();
    }
}

// 测试类
public class AbstractFactoryPatternDemo {
    public static void main(String[] args) {
        // 根据当前编程语言选择合适的日志记录器工厂
        LoggerFactory factory;
        String language = "Java"; // 可以从配置文件或命令行参数获取
        if (language.equalsIgnoreCase("Java")) {
            factory = new JavaLoggerFactory();
        } else if (language.equalsIgnoreCase("Python")) {
            factory = new PythonLoggerFactory();
        } else {
            throw new UnsupportedOperationException("Unsupported programming language");
        }

        LogManager logManager = new LogManager(factory);
        Logger logger = logManager.createLogger();
        logger.log("Hello, World!");
    }
}

在这两个场景中,我们都使用了抽象工厂模式来根据不同的条件动态地选择具体的实现类。在第一个场景中,我们使用抽象工厂模式来实现跨平台的UI组件库;在第二个场景中,我们使用抽象工厂模式来实现多种编程语言的日志记录器。通过使用抽象工厂模式,我们可以让代码更加简洁、易于维护,同时提高了代码的可扩展性和可重用性。