2010-03-23 8 views
30

A menudo me enfrento al problema de almacenar, en la memoria, algunos ajustes de configuración (posiblemente complejos) cargados desde archivos en el sistema de archivos. Me pregunto si hay una mejor manera de diseñar un patrón para este problema, sin embargo, que lo que he estado usando.¿Patrón de diseño para las propiedades de configuración cargadas una sola vez?

Esencialmente, mi solución actual implica tres pasos.

  1. Construye un singleton. Como los datos son persistentes y se garantiza que no se modificarán durante el tiempo de ejecución de la aplicación, solo se necesitará una sola instancia de objeto.

  2. Cuando se realiza la primera solicitud del objeto, cree el objeto y lea desde un archivo.

  3. Exponer datos con getters.

Esto tiene el efecto de que una gran parte de mi código es el siguiente: MyConfiguration.getInstance().getWeightOfBomb(), lo que parece bastante extraño para mí.

¿Hay una mejor manera de manejar esto de una manera más semántica?

Respuesta

29

Dependency Injection. No necesariamente tiene que usar un marco DI como Spring o Guice, pero realmente quiere evitar ensuciar su código con singletons. Aún puede usar un singleton en la implementación, pero no hay ninguna razón para que el resto de su código necesite saber que es un singleton. Los singletons son un gran dolor cuando se realizan pruebas unitarias y se refactorizan. Deje que su código haga referencia a una interfaz en su lugar. por ejemplo,

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

si se utiliza un marco DI, acaba de configuración le permite tener clases de su aplicación MyConfig inyectado. Si no lo hace, entonces el enfoque más perezoso que todavía tiene todas las ventajas es hacer algo como:

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

Realmente le toca a usted. Lo importante es que puede reemplazar myConfig por instancia cuando más tarde se da cuenta de que necesita variar el comportamiento y/o para probar la unidad.

+3

Una gran cantidad de veces, solo tengo que ajustar algunas propiedades de configuración en pequeñas aplicaciones de consola (que he estado escribiendo en masa, últimamente) . Sin embargo, en aplicaciones más grandes (para las que he adoptado este patrón), este método funciona bien. –

2

Propuesta adicional para la respuesta de noah.

Si no es conveniente que escriba un método para cada parámetro de configuración, puede usar enum para eso. Esto es lo que quiero decir:

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

}

Después de eso, si usted tiene un nuevo parámetro de configuración, todo lo que necesita hacer es añadir una nueva entrada de enumeración.

También puede extraer una interfaz de la clase de Configuración, por supuesto, moviendo enum fuera.

3

Se puede crear una interfaz para representar la configuración:

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

Y una implementación Singleton:

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

Y luego inyectar la configuración en sus clases:

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