2010-03-23 3 views
30

Я часто сталкиваюсь с проблемой хранения в памяти нескольких (возможно сложных) параметров конфигурации, загружаемых из файлов в файловой системе. Мне интересно, есть ли лучший способ архитектовать шаблон этой проблеме, чем то, что я использовал.Шаблон проектирования для одноразовых загруженных свойств конфигурации?

По существу, мое текущее решение включает в себя три шага.

  1. Построить одноэлементный. Поскольку данные постоянны и гарантированно не изменяются во время выполнения приложения, только один экземпляр объекта должен когда-либо понадобиться.

  2. Когда выполняется первый запрос для объекта, создайте объект и прочитайте его из файла.

  3. Экспозиция данных с геттерами.

Это приводит к тому, что многие из моего кода выглядит следующим образом: MyConfiguration.getInstance().getWeightOfBomb(), который выглядит довольно странно для меня.

Есть ли лучший способ справиться с этим более семантическим способом?

ответ

29

Инъекция зависимостей. Вам необязательно использовать фреймворк DI, например Spring или Guice, но вы действительно хотите избежать засорения вашего кода синглонами. Вы все еще можете использовать синглтон в реализации, но нет причин, по которым остальная часть вашего кода должна знать, что это синглтон. Синглтоны - огромная боль при модульном тестировании и рефакторинге. Пусть ваш код ссылается на интерфейс. например,

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

много раз, мне просто нужно обернуть некоторые свойства конфигурации в небольших консольных приложениях (которые я писал в массе, в последнее время) , Однако в более крупных приложениях (для которых я принял этот шаблон) этот метод работает хорошо. –

2

Дополнительное предложение для ответа noah.

Если вам неудобно написать метод для каждого параметра конфигурации, для этого вы можете использовать перечисление. Вот что я имею в виду:

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

}

После этого, если у вас есть новый параметр конфигурации, все, что вам нужно сделать, это добавить новую запись ENUM.

Вы также можете извлечь интерфейс из класса Configuration, конечно, перемещая перемычку снаружи.

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 
    } 
} 
Смежные вопросы