2009-07-29 10 views
5

Después de leer detenidamente los datos sobre singletons (el código huele, no el patrón) Me pregunto:¿Cómo puedo evitar/refactorizar los singletons malos en la práctica?

¿Cómo puedo refactorizar mi código para deshacerme de ellos?

A pesar de que casi todos aceptaron que los singletons malos son, bueno, malos, no pude encontrar ningún consejo práctico sobre cómo reemplazarlos. O es muy trivial o muy difícil.

Hay algunas maneras en que puedo pensar, pero todo parece inflar mi código tremendamente.

Por ejemplo, supongamos que tengo una clase "global" AppConfig que contiene información sobre la licencia del producto y describe las funciones disponibles para el usuario.

Lo que puedo pensar:

  • crear una clase base común para todos y cada clase de mis proyectos, que contiene una instancia AppConfig. (MALO: Imposible para los casos en los que ya tiene una clase base, por ejemplo, formularios)
  • Cree una interfaz común con un método setAppConfig.
  • Crear una AppConfigFactory mundial que puede crear AppConfig instancias (BAD: Sólo cambia el problema a otra clase)
  • pase la instancia como parámetro para cada método que lo necesita. (BAD: Código hinchazón)
  • ...

¿Qué puedo hacer yo?

EDIT: Aclaración: He identificado un single simple malo en mi código. Ahora quiero refactorizar mi código para eliminarlo. Estoy pidiendo consejos e ideas generales sobre cómo lograr esto.

+0

Parece un duplicado de http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used – Justicle

+1

No es un duplicado, al menos no de la pregunta que paró. No quiero saber el uso correcto o los pros y los contras de un singleton. Tengo un singleton malo que quiero eliminar y quiero saber la mejor manera de hacerlo. –

+0

http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/ –

Respuesta

6

Usar inyección de dependencias e inversión de marco de control: esto puede requerir una refactorización significativa. Luego, usando la dependencia de constructor o propiedad, solicite el "singleton"; idealmente, no lo pide todo, ya que según el principio de Demeter, solo debe pedir lo que realmente necesita (en su caso, la licencia). información).

Intento distinguir entre Singleton (el antipattern que oculta las variables globales) y singleton (es decir, algo que solo necesita uno). Un singleton verdadero se crea una vez al comienzo del programa (o en su fábrica) y se pasa a los objetos que lo necesitan.

+0

simplemente no entiendes el patrón de diseño singleton, ¡siempre deberías usar patrones de diseño! – IAdapter

+1

Realmente no puedo decirlo. ¿Estas siendo sarcastico? –

+0

¿Puedes dar algunos ejemplos de estos marcos? Algunas palabras clave que puedo buscar en google? –

0

¿Qué tal si la clase tiene solo miembros estáticos? Al igual que, en lugar de esto (código C#):

class AppConfig 
{ 
    public static readonly AppConfig Instance; 

    private AppConfig() { } 
    static AppConfig() 
    { 
     Instance = new AppConfig(); 
    } 

    public string SomeConfigParam { get; set; } 
} 

hacer esto:

static class AppConfig 
{ 
    public static string SomeConfigParam { get; set; } 
} 

Singleton sólo tienen sentido si se necesita pasar la instancia alrededor - como parámetros a funciones o valores en una colección. System.DBNull en .NET es un buen ejemplo de singleton. Si se trata simplemente de un almacén global de datos al que todos deberían poder acceder, las clases estáticas hacen que el código sea más corto y simple.

+0

tenga en cuenta que las clases estáticas pueden hacer que su código sea más difícil de detectar prueba. Aunque si se trata de un simple almacén de datos, ese no es el caso aquí. –

+0

¿No sería todavía un singleton? –

+2

No, es más como variables globales, excepto con un buen prefijo de espacio de nombres. Acéptalo: en cada programa habrá algunas variables globales. Configuración y datos a los que se debe acceder en todo el programa. Los miembros de clases/clases estáticas son la mejor manera de encapsularlos de una manera OOP. –

3

Usted dice

Crear una AppConfigFactory mundial que puede crear instancias appconfig (malo: sólo desplaza el problema a otra clase)

En mi opinión, esto es, en realidad, no está mal del todo. La opinión del cliente es que le pide a un objeto de fábrica la configuración que debería usar. Lo hace no sabe que es un singleton! De un golpe, el singleton-ness queda encapsulado en la fábrica. [Pragmáticamente, la fábrica bien puede terminar como un Singleton, pero todo tiene que arrancar, ¿verdad?]

Ahora, si completa el acceso a fábrica usando técnicas de inyección de dependencias es un refinamiento, lo fundamental es que solo un objeto es cuidando la creación de estos objetos AppConfig, solo la fábrica sabe si hay uno o muchos.

Y eso me lleva a otra teoría de mascotas ... no existe el número 1, cuando comienzas parece un Singleton, luego la conplexidad crece, y encuentras un escenario donde parte de tu aplicación (para ejemplo) utiliza una configuración y otra parte utiliza una diferente (por ejemplo, en transición dinámica entre versiones). La fábrica puede ocultar esa complejidad.

0

Pase el AppConfig a través del método setAppConfig() o el constructor, si el objeto necesita la configuración de la aplicación a lo largo de su vida útil. Si la asociación entre el AppConfig global y el objeto es condicional (es decir, se requiere solo en ciertos métodos), páselo como un argumento adicional.