设计模式与配置化:工厂模式创建配置对象、策略模式选择配置、建造者构建配置

说实话,做后端开发这么多年,我见过太多因为配置管理混乱导致的线上事故。有的项目把配置散落在代码的各个角落,改一个参数要翻遍十几个文件;有的项目配置对象初始化逻辑复杂到没人敢动。今天咱们就聊聊怎么用三个经典设计模式,把配置这件事做得既优雅又灵活。

为什么需要配置化?

先说说我的一个真实经历。几年前我接手过一个支付网关项目,里面光支付渠道的配置就有三十多个字段:超时时间、重试次数、回调地址、签名算法……每个渠道的配置还不一样。最要命的是,这些配置对象是通过一个巨大的 if-else 工厂方法创建的,每次新增渠道都要改那个方法,改完还要担心影响其他渠道。

你想想看,这种场景下,如果能把配置的创建、选择和构建过程拆分开,每个环节用最合适的模式去处理,是不是就清爽多了?

整体思路:三个模式各司其职

咱们先画一张图,看看这三个模式是怎么配合的:

配置化三模式协作流程 工厂模式 创建配置对象 根据类型实例化 策略模式 选择配置 运行时动态切换 建造者模式 构建配置 分步组装 核心思想 1. 工厂模式:屏蔽配置对象的创建细节,客户端只需传入类型标识 2. 策略模式:根据运行环境或用户选择,动态决定使用哪套配置 3. 建造者模式:处理复杂配置的组装过程,支持可选字段和默认值 三者组合:创建 → 选择 → 构建,形成完整的配置管理闭环 我在实际项目中,通常把这三个模式封装到一个 ConfigManager 中,对外只暴露一个 getConfig() 方法

这张图其实已经说得很清楚了。工厂模式负责「造出来」,策略模式负责「选哪个」,建造者模式负责「怎么拼」。咱们一个一个来看。

工厂模式:创建配置对象

工厂模式在这里的作用,说白了就是帮你把 new 对象的逻辑藏起来。我习惯用简单工厂或者工厂方法,具体看配置类型的数量。

举个例子,假设我们有数据库配置、缓存配置、消息队列配置三种:

// 配置接口
public interface Config {
    void validate();
}

// 数据库配置
public class DatabaseConfig implements Config {
    private String url;
    private String username;
    private String password;
    private int maxConnections;
    
    @Override
    public void validate() {
        if (url == null || url.isEmpty()) {
            throw new IllegalArgumentException("数据库URL不能为空");
        }
    }
    // getter/setter 省略
}

// 缓存配置
public class CacheConfig implements Config {
    private String host;
    private int port;
    private int expireSeconds;
    
    @Override
    public void validate() {
        if (host == null || host.isEmpty()) {
            throw new IllegalArgumentException("缓存主机地址不能为空");
        }
    }
    // getter/setter 省略
}

// 配置工厂
public class ConfigFactory {
    public static Config createConfig(String type) {
        switch (type) {
            case "database":
                return new DatabaseConfig();
            case "cache":
                return new CacheConfig();
            case "mq":
                return new MqConfig();
            default:
                throw new IllegalArgumentException("未知配置类型: " + type);
        }
    }
}
我的习惯:工厂方法里只做对象的创建和基础校验,不做复杂的初始化。复杂的初始化逻辑交给建造者去处理,这样职责更清晰。

策略模式:选择配置

策略模式解决的是「运行时动态选择」的问题。我记得之前做一个多租户系统,每个租户的配置策略都不一样——有的用默认配置,有的用自定义配置,还有的需要从远程配置中心拉取。

用策略模式来处理,简直不要太合适:

// 配置选择策略接口
public interface ConfigSelectionStrategy {
    Config select(String configType);
}

// 本地配置策略
public class LocalConfigStrategy implements ConfigSelectionStrategy {
    @Override
    public Config select(String configType) {
        // 从本地文件或数据库读取配置
        return ConfigFactory.createConfig(configType);
    }
}

// 远程配置策略
public class RemoteConfigStrategy implements ConfigSelectionStrategy {
    @Override
    public Config select(String configType) {
        // 从配置中心拉取(如 Apollo、Nacos)
        String remoteConfig = fetchFromConfigCenter(configType);
        return deserializeConfig(remoteConfig, configType);
    }
}

// 策略上下文
public class ConfigSelector {
    private ConfigSelectionStrategy strategy;
    
    public void setStrategy(ConfigSelectionStrategy strategy) {
        this.strategy = strategy;
    }
    
    public Config getConfig(String configType) {
        return strategy.select(configType);
    }
}
避坑指南:我曾经犯过一个错误,把策略的选择逻辑写死在代码里。后来发现每次切换策略都要改代码重新部署,太痛苦了。正确的做法是把策略的选择也配置化,比如通过配置文件或数据库来指定当前使用哪个策略。

建造者模式:构建配置

建造者模式是处理复杂配置的利器。你想想看,一个配置对象可能有十几个字段,有些是必填的,有些是选填的,有些还有默认值。如果用构造方法或者 setter 去设置,代码会变得又臭又长。

建造者模式可以让你像搭积木一样构建配置:

// 数据库配置的建造者
public class DatabaseConfigBuilder {
    private String url;
    private String username;
    private String password;
    private int maxConnections = 10;  // 默认值
    private int connectionTimeout = 5000;  // 默认值
    private boolean useSSL = false;  // 默认值
    
    public DatabaseConfigBuilder setUrl(String url) {
        this.url = url;
        return this;
    }
    
    public DatabaseConfigBuilder setUsername(String username) {
        this.username = username;
        return this;
    }
    
    public DatabaseConfigBuilder setPassword(String password) {
        this.password = password;
        return this;
    }
    
    public DatabaseConfigBuilder setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
        return this;
    }
    
    public DatabaseConfigBuilder setConnectionTimeout(int timeout) {
        this.connectionTimeout = timeout;
        return this;
    }
    
    public DatabaseConfigBuilder setUseSSL(boolean useSSL) {
        this.useSSL = useSSL;
        return this;
    }
    
    public DatabaseConfig build() {
        DatabaseConfig config = new DatabaseConfig();
        config.setUrl(this.url);
        config.setUsername(this.username);
        config.setPassword(this.password);
        config.setMaxConnections(this.maxConnections);
        config.setConnectionTimeout(this.connectionTimeout);
        config.setUseSSL(this.useSSL);
        config.validate();  // 构建时自动校验
        return config;
    }
}

// 使用示例
DatabaseConfig config = new DatabaseConfigBuilder()
    .setUrl("jdbc:mysql://localhost:3306/mydb")
    .setUsername("admin")
    .setPassword("123456")
    .setMaxConnections(20)
    .setUseSSL(true)
    .build();
注意:建造者模式虽然好用,但不要滥用。如果配置对象只有两三个字段,直接用构造方法或者 setter 反而更简单。我一般是在字段超过 5 个,或者有复杂的默认值逻辑时,才会考虑用建造者模式。

三者组合:完整的配置管理方案

把三个模式组合起来,就形成了一个完整的配置管理闭环。我通常的做法是这样的:

// 配置管理器
public class ConfigManager {
    private ConfigSelector selector;
    
    public ConfigManager() {
        this.selector = new ConfigSelector();
        // 根据环境选择策略
        String env = System.getProperty("app.env", "local");
        if ("local".equals(env)) {
            selector.setStrategy(new LocalConfigStrategy());
        } else {
            selector.setStrategy(new RemoteConfigStrategy());
        }
    }
    
    public <T extends Config> T getConfig(String configType, ConfigBuilder<T> builder) {
        // 1. 策略模式选择配置源
        Config rawConfig = selector.getConfig(configType);
        // 2. 建造者模式构建完整配置
        return builder.fromRawConfig(rawConfig).build();
    }
}

// 使用
ConfigManager manager = new ConfigManager();
DatabaseConfig dbConfig = manager.getConfig("database", new DatabaseConfigBuilder());

你看,客户端代码只需要两行就能拿到一个完整、校验过的配置对象。至于配置是从本地读还是从远程拉,配置对象是怎么一步步构建出来的,这些细节都被封装在了内部。

总结

这三个模式组合起来,解决的是配置管理中的三个核心问题:

  • 工厂模式:解决「怎么创建」的问题,把 new 的逻辑集中管理
  • 策略模式:解决「选哪个」的问题,支持运行时动态切换
  • 建造者模式:解决「怎么拼」的问题,让复杂对象的构建变得清晰

我个人觉得,这种组合方式最大的价值在于:它让配置的创建、选择和构建三个环节解耦了。每个环节都可以独立变化,互不影响。比如你想新增一个配置类型,只需要在工厂里加一个 case;想切换配置来源,只需要换一个策略;想调整配置的默认值,只需要改建造者。

嗯,这就是我在多个项目中沉淀下来的配置管理方案。希望能给你一些启发。


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