我经常面临在内存中存储从文件系统上的文件加载的一些(可能很复杂的)配置设置的问题。我想知道是否有更好的方法来构建一个模式来解决这个问题,然而,比我一直在使用的那样。
基本上,我目前的解决方案包括三个步骤。
建立一个单身人士。由于数据是持久的并且保证不会在应用程序的运行时间内发生变化,因此只需要一个对象实例。
当对该对象发出第一个请求时,创建该对象并从文件中读入。
使用getter公开数据。
这有很多我的代码看起来像这样:
MyConfiguration.getInstance().getWeightOfBomb()
,这看起来很奇怪。
有更好的方式以更加语义的方式处理这个问题吗?
答案 0 :(得分:34)
依赖注入。您不一定要使用像Spring或Guice这样的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类中提取界面,当然,也可以将枚举移到外面。