Spring + 设计模式 (二) 创建型 - 抽象工厂模式

83 阅读5分钟

抽象工厂模式

引言

抽象工厂模式是一种创建型设计模式,核心在于提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体类。它通过抽象工厂类定义一组工厂方法,每个方法负责创建一类产品,客户端只需通过工厂接口操作,轻松应对产品族的扩展。抽象工厂模式适用于需要统一管理多种产品组合的场景,强调系统的扩展性和一致性,字面“抽象”却带来无限可能。

实际开发中的用途

在实际开发中,抽象工厂模式常用于需要创建一组相关对象的场景,如跨平台的UI组件库、数据库驱动程序或多主题的报表生成系统。它解决了直接实例化带来的紧耦合问题,客户端代码只需依赖抽象工厂接口,轻松切换不同产品族(如从MySQL到PostgreSQL的数据库操作),提升系统的灵活性和可维护性。同时,它保证了产品之间的兼容性,特别适合复杂系统的模块化设计。

开发中的示例

设想一个报表生成系统,支持不同格式的报表(如PDF、Excel)。通过抽象工厂模式,可以定义一个报表工厂接口,包含生成报表和图表的工厂方法。客户端只需调用工厂接口,传入报表类型(如PDF),即可获取对应的报表和图表对象。这种方式隔离了具体实现,方便扩展新格式(如CSV),同时确保报表与图表风格一致。

Spring 源码中的应用

Spring 框架中,抽象工厂模式在 ApplicationContext 的实现中体现得淋漓尽致。ApplicationContext 作为一个抽象工厂,负责创建和管理一组相关的对象(如 Bean、MessageSource、Environment 等)。以 ClassPathXmlApplicationContext 为例,它通过配置文件创建一族对象,客户端无需关心具体实现。

以下是 Spring 源码的典型片段(ClassPathXmlApplicationContext.java):

// Spring 框架中的 ClassPathXmlApplicationContext
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh(); // 初始化工厂,创建一组相关对象
        }
    }

    @Override
    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
        // 配置 BeanDefinitionReader,解析 XML 并创建 Bean
        reader.setEnvironment(getEnvironment());
        reader.setResourceLoader(this);
        reader.setEntityResolver(new ResourceEntityResolver(this));
    }
}

在这段代码中,ClassPathXmlApplicationContext 作为抽象工厂,创建并管理一组相关对象(如 BeanDefinitionReaderEnvironment 等)。refresh() 方法协调这些对象的初始化,确保它们协同工作,形成一个完整的应用上下文。抽象工厂模式在这里解耦了客户端与具体对象创建过程,增强了 Spring IoC 容器的扩展性,允许无缝切换到其他上下文实现(如 AnnotationConfigApplicationContext)。

SpringBoot 代码案例

以下是一个基于 Spring Boot 2.7.6 的抽象工厂模式案例,模拟一个多主题的 UI 组件生成系统。系统支持不同主题(如暗黑、明亮)的按钮和文本框,确保同一主题的组件风格一致。

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

public interface TextBox {
    void display();
}

// 暗黑主题组件
public class DarkButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染暗黑主题按钮");
    }
}

public class DarkTextBox implements TextBox {
    @Override
    public void display() {
        System.out.println("显示暗黑主题文本框");
    }
}

// 明亮主题组件
public class LightButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染明亮主题按钮");
    }
}

public class LightTextBox implements TextBox {
    @Override
    public void display() {
        System.out.println("显示明亮主题文本框");
    }
}

// 抽象工厂接口
public interface UIFactory {
    Button createButton();
    TextBox createTextBox();
}

// 暗黑主题工厂
public class DarkUIFactory implements UIFactory {
    @Override
    public Button createButton() {
        return new DarkButton();
    }

    @Override
    public TextBox createTextBox() {
        return new DarkTextBox();
    }
}

// 明亮主题工厂
public class LightUIFactory implements UIFactory {
    @Override
    public Button createButton() {
        return new LightButton();
    }

    @Override
    public TextBox createTextBox() {
        return new LightTextBox();
    }
}

// Spring Boot 配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UIConfig {
    @Bean(name = "darkFactory")
    public UIFactory darkUIFactory() {
        return new DarkUIFactory();
    }

    @Bean(name = "lightFactory")
    public UIFactory lightUIFactory() {
        return new LightUIFactory();
    }
}

// Spring Boot 主程序
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application implements CommandLineRunner {
    @Autowired
    @Qualifier("darkFactory")
    private UIFactory darkFactory;

    @Autowired
    @Qualifier("lightFactory")
    private UIFactory lightFactory;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) {
        // 使用暗黑主题工厂
        Button darkButton = darkFactory.createButton();
        TextBox darkTextBox = darkFactory.createTextBox();
        darkButton.render(); // 输出:渲染暗黑主题按钮
        darkTextBox.display(); // 输出:显示暗黑主题文本框

        // 使用明亮主题工厂
        Button lightButton = lightFactory.createButton();
        TextBox lightTextBox = lightFactory.createTextBox();
        lightButton.render(); // 输出:渲染明亮主题按钮
        lightTextBox.display(); // 输出:显示明亮主题文本框
    }
}

这个案例通过 Spring Boot 的依赖注入,动态加载不同主题的 UI 工厂。UIFactory 接口定义了创建按钮和文本框的工厂方法,DarkUIFactoryLightUIFactory 分别生成暗黑和明亮主题的组件。客户端代码通过 Spring 的 @Autowired 注入工厂实例,轻松切换主题,同时保证组件风格一致。抽象工厂模式在这里降低了客户端与具体组件的耦合度,便于扩展新主题(如高对比度主题),提升了系统的可维护性。

总结

抽象工厂模式如同一场精心编排的交响乐,协调一组相关对象的创建,确保系统的高度一致性和扩展性。在 Spring 中,ApplicationContext 通过抽象工厂模式管理复杂对象的生命周期,赋予框架无与伦比的灵活性。结合 Spring Boot,开发者可以轻松实现动态切换的产品族,应对复杂业务需求。掌握抽象工厂模式,不仅能写出优雅的代码,更能设计出如 Spring 般可扩展的系统架构,真正做到“以不变应万变”。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢