一次性加载配置属性的设计模式?

时间:2010-03-23 20:46:33

标签: java design-patterns configuration

我经常面临在内存中存储从文件系统上的文件加载的一些(可能很复杂的)配置设置的问题。我想知道是否有更好的方法来构建一个模式来解决这个问题,然而,比我一直在使用的那样。

基本上,我目前的解决方案包括三个步骤。

  1. 建立一个单身人士。由于数据是持久的并且保证不会在应用程序的运行时间内发生变化,因此只需要一个对象实例。

  2. 当对该对象发出第一个请求时,创建该对象并从文件中读入。

  3. 使用getter公开数据。

  4. 这有很多我的代码看起来像这样: MyConfiguration.getInstance().getWeightOfBomb(),这看起来很奇怪。

    有更好的方式以更加语义的方式处理这个问题吗?

3 个答案:

答案 0 :(得分:34)

依赖注入。您不一定要使用像SpringGuice这样的DI框架,但您确实希望避免使用单例乱丢您的代码。您仍然可以在实现中使用单例,但没有理由其余代码需要知道它是单例。单元测试和重构时,单身人士是一个巨大的痛苦。让您的代码引用一个接口。如,

 interface MyConfig {
     double getWeightOfBomb();
 }

 class SomeClass {
    private MyConfig myConfig;

    public void doSomething() {
       myConfig.getWeightOfBomb();
    }
 }

 class MyConfigImpl implements MyConfig {
     public double getWeightOfBomb() {           
          return MyConfiguration.getInstance().getWeightOfBomb(); 
     }
 }

如果您使用DI框架,只需设置类以注入MyConfig实现。如果你不这样做,那么仍然具有所有好处的最懒惰的方法是做类似的事情:

 class SomeClass {
    private MyConfig myConfig = new MyConfigImpl();        
 }

真的,这取决于你。重要的是,当您稍后意识到需要改变行为和/或进行单元测试时,您可以在每个实例的基础上替换myConfig

答案 1 :(得分:4)

您可以创建一个界面来表示配置:

public interface Config {
    interface Key {}
    String get(Key key);
    String get(Key key, String defaultValue);
}

单例实现:

public enum MyConfig implements Config {
    INSTANCE("/config.properties");
    private final Properties config;

    MyConfig(String path) {
        config = new Properties();
        try {
            config.load(this.getClass().getResourceAsStream(path));
        } catch (IOException | NullPointerException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    @Override
    public String get(Config.Key key){
        return config.getProperty(key.toString());
    }

    @Override
    public String get(Config.Key key, String defaultValue) {
        return config.getProperty(key.toString(), defaultValue);
    }

    public enum Key implements Config.Key {
        PROXY_HOST("proxy.host"),
        PROXY_PORT("proxy.port");
        private final String name;

        Key(String name) { this.name = name; }    
        @Override
        public String toString() { return name; }
    }
}

然后在您的类中注入配置:

public class SomeClass  {
    private final Config config;

    public SomeClass(Config config) {
        this.config = config;
    }

    public void someMethod() {
        String host = config.get(Key.PROXY_HOST);
        String port = config.get(Key.PROXY_PORT, "8080");
        // Do something
    }
}

答案 2 :(得分:2)

诺亚回答的补充建议。

如果为每个配置参数编写方法不方便,那么可以使用枚举。这就是我的意思:

public class Configuration {

private final Properties properties;

public enum Parameter {
    MY_PARAMETER1("my.parameter1", "value1"),
    MY_PARAMETER2("my.parameter2", "value2");

    private final String name;
    private final String defaultValue;

    private Parameter(String name, String defaultValue) {
        this.name = name;
        this.defaultValue = defaultValue;
    }

    private String getName() {
        return name;
    }

    private String getDefaultValue() {
        return defaultValue;
    }
}


public Configuration(Properties properties) {
    this.properties = (Properties)properties.clone();
}

//single method for every configuration parameter
public String get(Parameter param) {
    return properties.getProperty(param.getName(), param.getDefaultValue());
}

}

之后,如果你有一个新的配置参数,你需要做的就是添加一个新的枚举条目。

您还可以从Configuration类中提取界面,当然,也可以将枚举移到外面。