Config Class / Struct: ¿Patrón o antipatrón? ¿Alternativas?

10

Si agrega nuevas opciones de configuración a un programa, a menudo puede tener toneladas de efectos de onda en términos de llevar las opciones a donde deben actuar. Hay tres formas básicas de lidiar con esto que conozco:

  1. Pase todas las configuraciones a las partes de su programa que las necesitan explícitamente como primitivas. Esta es la forma más explícita y la forma en que más desacopla las cosas. La desventaja es que esto es a la vez detallado y quebradizo.

  2. Haga que los ajustes de configuración más utilizados sean globales / estáticos. Esta es la forma más simple, pero introduce acción a distancia, dificulta la capacidad de prueba y asume que la configuración realmente es global (que solo desearía una configuración en un momento dado).

  3. Cree una clase / estructura de configuración que contenga todas las opciones de configuración para todo el programa o para cada preocupación importante dentro del programa, y ​​luego pase esto explícitamente. Esto es menos explícito que (1) pero más explícito que (2). Si desea cambiar una configuración solo para una llamada de función, puede clonar el objeto de configuración y cambiar este valor. Esto es útil tanto en pruebas como en la práctica. Sin embargo, aún puede pasar toneladas de información a una función que no necesita y cambiar un valor en la clase / estructura de configuración aún puede causar acción a distancia.

¿Consideraría (3) un patrón o un antipatrón? Si es un antipatrón, ¿qué haces en su lugar?

dsimcha
fuente
¿Qué tal una variación en 3 - tener varias clases de configuración, pasando la apropiada a donde se necesita?
Oded
@Oded: quise enfatizar eso como una posibilidad. Editado
dsimcha

Respuestas:

4

La mejor solución sería hacer varias interfaces de configuración e implementarlas como desee. Esto limita la accesibilidad y mantiene las cosas localizadas. Sin embargo, es demasiado esfuerzo para que valga la pena, simplemente tirando toda la configuración en una sola clase y pasando a un problema con mucha más gravedad. Esta es la configuración, no el UtterlyCrucialAlwaysChangingClass, prácticamente se mantendrá igual. Mientras no lo haga todo global, y la implementación sea consistente, no me preocuparía.

DeadMG
fuente
44
+1 por decir que algo no es un diseño teóricamente ideal, pero podría ser bueno en la práctica cuando se considera la simplicidad y la probabilidad de cambio (o falta de él).
dsimcha
Acabo de lanzar cuatro argumentos y lo reemplacé con una clase de Configuración. Se sintió como lo correcto.
Martin Ueding
No entiendo cuál de las 3 opciones está defendiendo. ¿Podría por favor especificar?
DBedrenko
1

Prefiero su opción 1 porque el desacoplamiento permite una prueba más fácil y la configuración de la que depende el objeto se hace explícita. Si un objeto requiere un ajuste de configuración, entonces explíquelo explícitamente al objeto mediante un argumento de constructor o un método de establecimiento. Reduzca la verbosidad mediante el uso de un marco de inyección de dependencia para inyectar esas configuraciones en el objeto.

Jim Huang
fuente
Te has contradicho a ti mismo: dices usar la Opción 1, pero luego dices "Reduce la verbosidad usando un marco de inyección de dependencia para inyectar esos ajustes de configuración en el objeto". que es la opción 3: inyección de constructor.
DBedrenko
0

Imagínese si su archivo de configuración fue escrito en XML. Luego, podría pasar fragmentos de este XML a cada uno de sus componentes, para que obtengan sus datos de configuración.

Si está utilizando .NET, puede crear clases con DataContracts que puede usar XmlSerialiser para crear una jerarquía de objetos desde su configuración Xml, y pasar estos objetos como configuración.

Esto luego te presenta el siguiente problema. Sus datos de configuración tienen tres partes diferentes. La configuración de la aplicación estructural que organiza sus bibliotecas de códigos para que se comporten como este producto específico. La configuración del sitio que contiene la configuración específica de su instalación y las preferencias de usuario / datos de configuración que varían con cada usuario en su sistema.

Saber qué parte es cuál y mantener estas configuraciones de datos separadas hará que la instalación de actualizaciones sea mucho más simple (sin perder la configuración de los clientes)

Michael Shaw
fuente
0

Haría que la clase en la opción # 3 sea estática. Entonces en lugar de

//create SomeCl
Foo f = new Foo();
f.setConfigInst(cfg);
...
...
//Inside Foo
public void setConfig(MyAppConfig c) { localCfg = c; }
...
//somewhere else:
x = localCfg.getConfigForX();

Solo puedes tener:

//Inside Foo
x = MyAppConfig.getConfigForX();

Deje que los detalles de cargar / guardar datos de configuración sucedan dentro de la MyAppConfigclase. Y, por supuesto, podría tener variaciones más complejas, como diferentes clases para diferentes propósitos.

El único caso en el que este enfoque sería un problema sería si, por alguna razón, necesitara trabajar en varias instancias de diferentes configuraciones al mismo tiempo , aunque todavía no me he encontrado con tal situación.

FrustratedWithFormsDesigner
fuente
1
Que es lo que sucede cuando se ejecutan pruebas unitarias en algunos marcos de prueba ... Pero incluso sin pruebas unitarias explícitamente paralelas, va a ser una molestia para los objetos de prueba unitarios que dependen del estado global.
Péter Török
0

Estoy trabajando en un proyecto en el que estamos utilizando el enfoque de "3 capas (interfaz, lógica de negocios, acceso a datos)". La aplicación puede ser un servidor web multiusuario o un servidor cliente.

Trabajamos con 3 configuraciones diferentes, la primera específica para la PC, cuando el usuario está trabajando. El segundo específico para el usuario actual, y una tercera configuración global para todos los usuarios y aplicaciones cliente.

Cada configuración está representada en cada instancia de la aplicación por un objeto.

Este enfoque puede ayudar a su proyecto.

umlcat
fuente