2010-03-23 31 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 
    } 
}