2010-03-23 71 views
30

我经常遇到在内存中存储从文件系统上的文件加载的一些(可能是复杂的)配置设置的问题。我想知道是否有更好的方法来构建一个模式来解决这个问题,但是,比我一直在使用的方式。一次性加载配置属性的设计模式?

本质上,我目前的解决方案涉及三个步骤。

  1. 建立一个单身人士。由于数据是持久的,并且保证不会通过应用程序的运行时更改,所以只需要一个对象实例。

  2. 当第一次请求对象时,创建对象并从文件读入。

  3. 用getter公开数据。

这有很多我的代码看起来像这样的效果: MyConfiguration.getInstance().getWeightOfBomb(),这看起来相当奇怪了吧。

有没有更好的方式来处理这个更多的语义方式?

回答

29

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

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,稍后您会意识到需要改变行为和/或进行单元测试。

+3

很多的时候,我只需要在小型控制台应用程序中包装一些配置属性(最近我一直在写这些应用程序) 。在较大的应用程序中,虽然(我已采用此模式),但此方法运行良好。 – 2010-03-24 14:06:50

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()); 
} 

}

之后,如果你有一个新的配置参数,所有你需要做的是增加一个新的枚举项。

您还可以从配置类中提取接口,当然还需要在外部移动枚举。

3

你可以创建一个接口来表示的配置:

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 
    } 
}