对象工厂模式:从基础到Spring FactoryBean

对象工厂模式,说白了就是帮你创建对象的。你可能会想:「这不就是new一下吗?」嗯,在简单场景下确实如此。但当你面对复杂的对象创建逻辑、需要解耦调用方和实现类时,工厂模式就成了你的好帮手。

我个人习惯把工厂模式看作「对象的代工厂」。你告诉工厂你要什么,它给你造出来,你不用关心造的过程有多复杂。今天我们就从最基础的工厂接口讲起,一直聊到Spring的FactoryBean。

工厂接口:定义契约

工厂接口是整个模式的基石。它定义了一个统一的创建方法,所有具体工厂都必须实现它。

// Java版本
public interface ObjectFactory<T> {
    T create();
}

// C++版本
template<typename T>
class ObjectFactory {
public:
    virtual ~ObjectFactory() = default;
    virtual T* create() = 0;
};

为什么要有接口?我在项目中遇到过这样的场景:一开始直接new对象,后来需求变了,需要从配置文件读取参数来创建。如果当初用了工厂接口,只需要新增一个实现类,调用方代码一行都不用改。这就是面向接口编程的魅力。

具体工厂:实现创建逻辑

具体工厂负责实际的创建过程。这里可以包含复杂的初始化逻辑、参数校验、缓存策略等。

// Java版本
public class DatabaseConnectionFactory implements ObjectFactory<Connection> {
    private final String url;
    private final String username;
    private final String password;
    
    public DatabaseConnectionFactory(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }
    
    @Override
    public Connection create() {
        // 这里可以加入连接池、重试机制等复杂逻辑
        return DriverManager.getConnection(url, username, password);
    }
}

// C++版本
class MySqlConnectionFactory : public ObjectFactory<DatabaseConnection> {
private:
    std::string host_;
    int port_;
    std::string user_;
    std::string password_;
    
public:
    MySqlConnectionFactory(const std::string& host, int port,
                          const std::string& user, const std::string& password)
        : host_(host), port_(port), user_(user), password_(password) {}
    
    DatabaseConnection* create() override {
        // 实际项目中这里会调用数据库驱动库
        return new DatabaseConnection(host_, port_, user_, password_);
    }
};

个人经验:具体工厂里不要只做简单的new。我习惯把对象生命周期管理、依赖注入、配置加载都放在工厂里。这样工厂就成了对象的「全权代理人」。

产品创建:从简单到复杂

产品创建可以很简单,也可以很复杂。关键在于:调用方不需要知道这些复杂性。

// 使用示例
public class Application {
    private final ObjectFactory<ReportGenerator> factory;
    
    public Application(ObjectFactory<ReportGenerator> factory) {
        this.factory = factory;
    }
    
    public void generateReport() {
        ReportGenerator generator = factory.create();
        generator.generate();
    }
}

// 调用方只需要知道工厂接口,不需要知道具体实现
public static void main(String[] args) {
    ObjectFactory<ReportGenerator> factory = new PdfReportFactory();
    Application app = new Application(factory);
    app.generateReport();
}

你想想看,如果哪天要把PDF换成Excel,只需要换一个工厂实现。调用方Application完全不用改。这就是工厂模式的核心价值——解耦。

Spring FactoryBean:工厂模式的进阶应用

说到工厂模式,就不得不提Spring的FactoryBean。它本质上就是工厂模式在Spring IoC容器中的具体实现。

// Spring FactoryBean示例
@Component
public class MyServiceFactoryBean implements FactoryBean<MyService> {
    
    @Override
    public MyService getObject() throws Exception {
        // 这里可以执行复杂的初始化逻辑
        MyService service = new MyService();
        service.setConfig(loadConfig());
        service.init();
        return service;
    }
    
    @Override
    public Class<?> getObjectType() {
        return MyService.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true; // 默认返回单例
    }
    
    private Config loadConfig() {
        // 从配置文件或数据库加载配置
        return new Config();
    }
}

关键点:FactoryBean和普通Bean的区别在于:普通Bean直接由Spring容器管理生命周期,而FactoryBean允许你在创建过程中插入自定义逻辑。Spring容器管理的是FactoryBean本身,而getObject()返回的是你真正需要的对象。

我曾经踩过一个坑:在FactoryBean的getObject()方法里调用了其他Bean的方法,结果造成了循环依赖。嗯,这里要注意——FactoryBean的创建时机比普通Bean早,如果依赖了其他需要延迟初始化的Bean,很容易出问题。

工厂模式的核心结构

下面这张图展示了对象工厂模式的整体结构,以及Spring FactoryBean在其中的位置:

对象工厂模式结构图 ObjectFactory<T> + create(): T PdfReportFactory + create(): PdfReport ExcelReportFactory + create(): ExcelReport MyServiceFactoryBean + getObject(): MyService PdfReport ExcelReport MyService 调用方 (Application) 工厂接口 具体工厂 FactoryBean 产品对象 调用方

工厂模式的应用场景

场景 说明 推荐使用
对象创建逻辑复杂 需要多步初始化、参数校验、资源加载 工厂模式
需要解耦调用方和实现类 调用方不关心具体实现,只依赖接口 工厂模式 + 依赖注入
需要集中管理对象生命周期 单例、池化、延迟加载等策略 FactoryBean 或自定义工厂
需要根据配置动态创建对象 从配置文件、数据库读取创建参数 工厂模式 + 反射/模板

避坑指南:我曾经在一个项目里过度使用工厂模式,每个类都配一个工厂,结果代码量翻了三倍。记住:工厂模式是为了解决复杂创建问题,如果只是简单的new,直接用就好了。不要为了模式而模式。

工厂模式与Spring FactoryBean的对比

特性 传统工厂模式 Spring FactoryBean
管理方式 手动管理工厂实例 由Spring IoC容器管理
生命周期 需要手动控制 自动管理,支持单例/原型
依赖注入 需要手动注入依赖 自动注入,支持AOP
灵活性 完全自定义 受限于Spring容器
适用场景 非Spring项目或需要完全控制 Spring项目中的复杂Bean创建

我个人更倾向于在Spring项目中使用FactoryBean来处理那些「创建过程比较复杂」的Bean。比如需要从数据库加载配置、需要执行远程调用初始化、或者需要根据环境动态选择实现类。这些场景用FactoryBean再合适不过了。

小技巧:如果你在Spring中只是需要根据配置创建不同的实现,可以考虑用@Conditional注解,比FactoryBean更轻量。FactoryBean更适合那些创建逻辑本身就很复杂的场景。

好了,关于对象工厂模式就聊到这里。从基础的工厂接口到Spring的FactoryBean,核心思想始终没变:把对象的创建过程封装起来,让调用方专注于业务逻辑。记住这个原则,你就能用好工厂模式。

公众号:蓝海资料掘金营,微信deep3321