2010-07-03 31 views
7

He sido desarrollador web desde hace algún tiempo utilizando ASP.NET y C#, quiero probar y aumentar mis habilidades mediante el uso de las mejores prácticas.Alternativas para el patrón singleton?

Tengo un sitio web. Quiero cargar la configuración una vez, y solo hacer referencia donde sea que la necesite. Así que investigué y el 50% de los desarrolladores parecen estar usando el patrón singleton para hacer esto. Y el otro 50% de los desarrolladores son ant-singleton. Todos odian a los solteros. Recomiendan la inyección de dependencia.

¿Por qué los singleton son malos? ¿Cuál es la mejor práctica para cargar configuraciones de sitios web? ¿Deberían cargarse solo una vez y hacer referencia a ellos cuando sea necesario? ¿Cómo podría hacer esto con la inyección de dependencia (soy nuevo en esto)? ¿Hay alguna muestra que alguien pueda recomendar para mi escenario? Y también me gustaría ver algún código de prueba unitaria para esto (para mi escenario).

Gracias Brendan

+0

posible duplicado de [¿Hay alguna alternativa viable al patrón GOF Singleton?] (Http://stackoverflow.com/questions/162042/are-herehere-any-viable-alternatives-to-the-gof-singleton- patrón) –

Respuesta

6

Generalmente, evito los singleton porque dificultan la prueba de la unidad de su aplicación. Los Singletons son difíciles de simular para las pruebas unitarias precisamente por su naturaleza: siempre obtendrá el mismo, no uno que pueda configurar fácilmente para una prueba unitaria. Sin embargo, la configuración de los datos de configuración fuertemente tipados es una excepción. Por lo general, los datos de configuración son relativamente estáticos y la alternativa implica escribir una buena cantidad de código para evitar las clases estáticas que el marco proporciona para acceder a web.config de todos modos.

Hay un par de maneras diferentes de usarlo que aún le permitirán probar su aplicación. Una forma (quizás en ambos sentidos, si su singleton no lee perezosamente la aplicación.cofnig) es tener un archivo app.config predeterminado en su proyecto de prueba unitario que proporcione los valores predeterminados requeridos para sus pruebas. Puede usar la reflexión para reemplazar cualquier valor específico según sea necesario en las pruebas de su unidad. Normalmente, configuro un método privado que permite que se elimine la instancia de singleton privada en la configuración de prueba si realizo cambios para pruebas particulares.

Otra forma es no utilizar el singleton directamente, sino crear una interfaz que implemente la clase singleton. Puede utilizar la inyección manual de la interfaz, por defecto a la instancia singleton si el valor suministrado es nulo. Esto le permite crear una instancia simulada que puede pasar a la clase bajo prueba para sus pruebas, pero en su código real use la instancia singleton. Esencialmente, cada clase que lo necesita mantiene una referencia privada a la instancia de singleton y la usa. Me gusta de esta manera un poco mejor, pero dado que se creará el singleton, es posible que aún necesite el archivo app.config predeterminado, a menos que todos los valores estén cargados de forma laxa.

public class Foo 
{ 
    private IAppConfiguration Configuration { get; set; } 

    public Foo() : this(null) { } 

    public Foo(IAppConfiguration config) 
    { 
     this.Configuration = config ?? AppConfiguration.Instance; 
    } 

    public void Bar() 
    { 
     var value = this.Config.SomeMaximum; 
     ... 
    } 
}  
+0

Lo siento tan tarde. comentarios interesantes sobre Datos de configuración como una excepción. Normalmente tomo el enfoque opuesto. Intento implementar mi configuración de tiempo de ejecución como interfaces e inyectarlas a la aplicación al inicio. De esta manera, mi programa solo depende de las interfaces en sí, que son libres de cambiar o se burlan de las pruebas. Al inicio, necesito leer objetos usando ConfigurationManager, pero este es el único lugar que conoce esa clase estática. – user734929

+0

Este es el enfoque que he migrado también, aunque mi interfaz de configuración está registrada como singleton en mi contenedor DI para lo mejor de ambos mundos. Sin embargo, todavía se trata del único ejemplo de implementación de Singleton con el que me siento cómodo. – tvanfosson

1

Hay una buena discusión de los patrones únicos, y los ejemplos de codificación aquí ... http://en.wikipedia.org/wiki/Singleton_pattern Ver también aquí ... http://en.wikipedia.org/wiki/Dependency_injection

Por alguna razón, parecen únicos para dividir los programadores en un fuerte pro - y anti-campamentos. Sean cuales sean los méritos del enfoque, si sus colegas están en contra, probablemente sea mejor no usar uno. Si estás solo, pruébalo y mira.

+0

Quiero probarlo también, ¿pero no tengo idea de cómo probar un patrón singleton? –

1

Diseño Patrones pueden ser cosas increíbles. Desafortunadamente, el singleton parece sobresalir como un pulgar dolorido y en muchos casos puede considerarse un antipatrón (promueve malas prácticas). Bizarely, la mayoría de los desarrolladores solo conocerán un patrón de diseño, y ese es el singleton.

Idealmente, su configuración debe ser una variable miembro en una ubicación de alto nivel, por ejemplo, el objeto de la aplicación que posee las páginas web que está generando. Las páginas pueden solicitar a la aplicación la configuración o la aplicación puede pasar las configuraciones a medida que se construyen las páginas.

+0

En el curso de patrones de diseño al que asistí, el singleton fue el primero que se enseñó. Esa podría ser la razón por la cual todo el mundo lo recuerda. –

+3

@Brian: Y ese patrón se describe en http://sites.google.com/site/steveyegge2/singleton-considered-stupid – wRAR

+0

¿Tiene un código de muestra de lo que describió? O un enlace? –

0

Una forma de abordar este problema es eliminarlo como un problema DAL.

Cualquiera que sea la clase/página web, etc. que necesite para usar las configuraciones debería declarar una dependencia en un IConfigSettingsService (factory/repository/whatever-you-like-to-call-them).

private IConfigSettingsService _configSettingsService; 

public WebPage(IConfigSettingsService configSettingsService) 
{ 
    _configSettingsService = configSettingsService; 
} 

Por lo que su clase sería obtener la configuración de esta manera:

ConfigSettings _configSettings = _configSettingsService.GetTheOnlySettings(); 

la implementación ConfigSettingsService tendría una dependencia que es de clase Dal. ¿Cómo poblaría Dal el objeto ConfigSettings? A quién le importa.

  • Tal vez sería rellenar una ConfigSettings desde un archivo XML base de datos o .config, cada vez.

  • Tal vez lo haga la primera vez pero luego complete un _configSettings estático para las llamadas siguientes.

  • Tal vez obtendría la configuración de Redis. Si algo indica que la configuración ha cambiado, entonces el dal, o algo externo, puede actualizar Redis. (Este enfoque será útil si tiene más de una aplicación a través de la configuración.

Sea lo que hace, su única dependencia es una interfaz de servicio no Singleton. Eso es muy fácil de burlar. En las pruebas se puede hacer que devuelva ConfigSettings con lo que quieras en él).

En realidad, sería más probable que MyPageBase tenga la dependencia IConfigSettingsService, pero podría ser fácilmente un servicio web, servicio de Windows, MVC somewhatsit o todo lo anterior.

Cuestiones relacionadas