Tenemos una clase que contiene información de configuración para la aplicación. Solía ser un singleton. Después de una revisión arquitectónica, nos dijeron que elimináramos el singleton. Vimos algunos beneficios de no usar singleton en las pruebas unitarias porque podemos probar diferentes configuraciones a la vez.
Sin singleton, tenemos que pasar la instancia por todas partes en nuestro código. Se está poniendo tan complicado que escribimos una envoltura de singleton. Ahora estamos portando el mismo código a PHP y .NET, me pregunto si hay un patrón mejor que podamos usar para el objeto de configuración.
fuente
La mejor forma es utilizar un patrón de fábrica. Cuando construye una nueva instancia de su clase (en la fábrica), puede insertar los datos 'globales' en el objeto recién construido, ya sea como una referencia a una sola instancia (que almacena en la clase de fábrica) o copiando los datos relevantes datos en el nuevo objeto.
Todos sus objetos contendrán los datos que solían vivir en el singleton. No creo que haya mucha diferencia en general, pero puede hacer que su código sea más fácil de leer.
fuente
Podría estar diciendo lo obvio aquí, pero ¿hay alguna razón por la que no pueda usar un marco de inyección de dependencia como Spring o Guice ? (Creo que Spring también está disponible para .NET ahora).
De esa manera, el marco puede contener una sola copia de los objetos de configuración y sus beans (servicios, DAO, lo que sea) no tienen que preocuparse por buscarlos.
¡Este es el enfoque que suelo tomar!
fuente
Si usa Spring Framework , puede crear un bean regular. De forma predeterminada (o si lo establece explícitamente
scope="singleton"
) solo se crea una instancia del bean y esa instancia se devuelve cada vez que el bean se utiliza en una dependencia o se recupera mediantegetBean()
.Obtiene la ventaja de la instancia única, sin el acoplamiento del patrón Singleton.
fuente
La alternativa es pasar lo que necesita en lugar de pedirle cosas a un objeto.
fuente
no acumule responsabilidades en un solo objeto de configuración, ya que terminará en un objeto muy grande, difícil de entender y frágil.
Por ejemplo, si necesita otro parámetro para una clase en particular, cambia el
Configuration
objeto y luego recompila todas las clases que lo usan. Esto es algo problemático.Intente refactorizar su código para evitar un objeto común, global y grande
Configuration
. Pase solo los parámetros requeridos a las clases de cliente:debe refactorizarse para:
un marco de inyección de dependencia ayudará mucho aquí, pero no es estrictamente necesario.
fuente
Puede lograr el mismo comportamiento de singleton utilizando métodos estáticos. Steve yegge lo explica muy bien en este post.
fuente
¿Es posible una clase que contenga solo métodos y campos estáticos? No estoy seguro de cuál es exactamente su situación, pero valdría la pena investigarla.
fuente
Depende de qué herramientas / marcos, etc. se estén utilizando. Con las herramientas de inyección de dependencia / ioc, a menudo se puede obtener rendimiento / optimizaciones de singleton haciendo que el contenedor di / ioc use el comportamiento de singleton para la clase requerida (como una interfaz IConfigSettings) creando solo una instancia de la clase. Esto aún podría sustituirse por pruebas
Alternativamente, uno podría usar una fábrica para crear la clase y devolver la misma instancia cada vez que la solicite, pero para probar, podría devolver una versión stubned / simulada
fuente
Revise la posibilidad de realizar la configuración como interfaz de devolución de llamada. Entonces su código sensible a la configuración se verá:
El código de inicio del sistema se verá:
fuente
Podría usar un marco de inyección de dependencia para aliviar el dolor de pasar el objeto de configuración. Uno decente es ninject, que tiene la ventaja de usar código en lugar de xml.
fuente
Tal vez tampoco sea muy limpio, pero tal vez podría pasar los bits de información que desea cambiar al método que crea el singleton, en lugar de usar
puede llamar
createSingleton(Information info)
directamente al inicio de la aplicación (y en los métodos de configuración de las pruebas unitarias).fuente
Los singleton no son malvados, pero el patrón de diseño es defectuoso. Tengo una clase de la que solo quiero crear una instancia única durante el tiempo de ejecución, pero quiero crear varias instancias aisladas durante las pruebas unitarias para garantizar resultados deterministas.
DI usando Spring, etc., es una muy buena opción, pero no la única.
fuente