¿Cuándo debería usar el patrón singleton en lugar de una clase estática? [cerrado]

85

Nombre las consideraciones de diseño al decidir entre el uso de un singleton o una clase estática. Al hacer esto, se ve obligado a contrastar los dos, por lo que cualquier contraste que se le ocurra también es útil para mostrar su proceso de pensamiento. Además, a todos los entrevistadores les gusta ver ejemplos ilustrativos. :)

cdleary
fuente
una clase java no puede hacer estática a menos que sea una clase interna
Harshana
1
Si el estado del objeto es importante, use singleton; de lo contrario, use una clase estática.
Levent Divilioglu,

Respuestas:

80
  • Los singleton pueden implementar interfaces y heredar de otras clases.
  • Los singleton pueden cargarse de forma diferida. Solo cuando sea realmente necesario. Eso es muy útil si la inicialización incluye costosas conexiones de base de datos o carga de recursos.
  • Los singleton ofrecen un objeto real.
  • Los singleton se pueden extender a una fábrica. La administración de objetos detrás de escena es abstracta, por lo que se puede mantener mejor y da como resultado un mejor código.
Tobias
fuente
2
Eche un vistazo a este enlace también: codeofdoom.com/wordpress/2008/04/20/…
Amit
4
"Los singleton se pueden cargar de forma diferida": en C #, el constructor estático solo se llama la primera vez que se hace referencia a un miembro estático. En PHP, puede usar la carga automática para que solo se ejecute la primera vez que se use la clase.
mpen
Las inicializaciones estáticas de Java también son perezosas. No hay puntos para Singletons allí.
MikeFHay
13

¿Qué tal "evitar ambos"? Singletons y clases estáticas:

  • Puede introducir estado global
  • Conéctese estrechamente a muchas otras clases
  • Ocultar dependencias
  • Puede dificultar las clases de pruebas unitarias de forma aislada

En su lugar, busque en la inyección de dependencia y la inversión de las bibliotecas de contenedores de control . Varias de las bibliotecas de IoC se encargarán de la gestión de por vida por usted.

(Como siempre, hay excepciones, como clases de matemáticas estáticas y métodos de extensión de C #).

TrueWill
fuente
1
Pequeñas liendres: las clases singleton son compatibles con las técnicas de inyección de dependencia (solo inyéctelas en sus clases dependientes y no necesitan codificar nada); esto permite burlarse y probar de forma aislada. También son un patrón de diseño válido para administrar recursos que se sabe que son limitados en toda la plataforma. (El ejemplo clásico es impresoras que no tienen una gestión de contención.)
cdleary
@cdleary - de acuerdo; sin embargo, la implementación clásica a menudo deja Singleton.getInstance () en todo el código base. Los "singletons" para administrar recursos, cachés, etc. se pueden implementar con POCOs / POJOs y marcos de contenedores IoC que admiten la administración de por vida (registre el tipo como contenedor de vida y cada resolución obtendrá la misma instancia).
TrueWill
9
Si desea darle a sus Singletons un entierro adecuado, vaya a singletonfuneralservice.com
TrueWill
1
Hide Dependencieslittle sideinfo sobre este punto: puede implementar el patrón de inversión de control, por ejemplo, utilizando Ninject . Esto le permite usar solo una instancia de un tipo al vincularlo a a SingletonScope, lo que significa que siempre inyectará la misma instancia, pero la clase no será singleton.
LuckyLikey
8

Yo diría que la única diferencia es la sintaxis: MySingleton.Current.Whatever () vs MySingleton.Whatever (). El estado, como mencionó David, es en última instancia "estático" en cualquier caso.


EDITAR: La brigada de enterramiento vino de Digg ... de todos modos, pensé en un caso que requeriría un singleton. Las clases estáticas no pueden heredar de una clase base ni implementar una interfaz (al menos en .Net no pueden). Entonces, si necesita esta funcionalidad, debe usar un singleton.

xanadont
fuente
7

Una de mis discusiones favoritas sobre este tema está aquí (sitio original caído, ahora vinculado a Internet Archive Wayback Machine ).

Para resumir las ventajas de flexibilidad de un Singleton:

  • un Singleton se puede convertir fácilmente en una fábrica
  • un Singleton se puede modificar fácilmente para devolver diferentes subclases
  • esto puede resultar en una aplicación más fácil de mantener
nuevo dia
fuente
5

Una clase estática con una carga de variables estáticas es un truco.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

Un singleton con una instancia real es mejor.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

El estado está SOLO en la instancia.

Por lo tanto, el singleton se puede modificar más tarde para hacer agrupaciones, instancias locales de subprocesos, etc. Y no es necesario cambiar nada del código ya escrito para obtener el beneficio.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

Es posible hacer algo similar con una clase estática, pero habrá una sobrecarga por llamada en el envío indirecto.

Puede obtener la instancia y pasarla a una función como argumento. Esto permite que el código se dirija al singleton "correcto". Sabemos que solo necesitará uno ... hasta que no lo necesite.

El gran beneficio es que los singleton con estado se pueden convertir en seguros para subprocesos, mientras que una clase estática no, a menos que la modifique para que sea un singleton secreto.

Tim Williscroft
fuente
4

Piense en un singleton como un servicio. Es un objeto que proporciona un conjunto específico de funciones. P.ej

ObjectFactory.getInstance().makeObject();

La fábrica de objetos es un objeto que realiza un servicio específico.

Por el contrario, una clase llena de métodos estáticos es una colección de acciones que tal vez desee realizar, organizadas en un grupo relacionado (la clase). P.ej

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

El ejemplo de StringUtils aquí es una colección de funcionalidades que se pueden aplicar en cualquier lugar. El objeto singleton factory es un tipo específico de objeto con una clara responsabilidad que puede crearse y transmitirse donde sea necesario.

izb
fuente
4

Las clases estáticas se instancian en tiempo de ejecución. Esto puede llevar mucho tiempo. Se pueden crear instancias de singletons solo cuando sea necesario.

dmo
fuente
13
Los singleton también se crean en tiempo de ejecución ...
recursivo
1
@recursive: se puede controlar la instanciación de singleton.
Nikit Batale
3
quizás una mejor palabra sería inicialización (en lugar de instanciación)
Marlon
3

Los singletons no deben usarse de la misma manera que las clases estáticas. En esencia,

MyStaticClass.GetInstance().DoSomething();

es esencialmente lo mismo que

MyStaticClass.DoSomething();

Lo que debería estar haciendo es tratar el singleton como un objeto más . Si un servicio requiere una instancia del tipo singleton, pase esa instancia en el constructor:

var svc = new MyComplexServce(MyStaticClass.GetInstance());

El servicio no debe ser consciente de que el objeto es un singleton y debe tratar el objeto como solo un objeto.

El objeto ciertamente se puede implementar, como un detalle de implementación y como un aspecto de la configuración general, como un singleton si eso facilita las cosas. Pero las cosas que usan el objeto no deberían tener que saber si el objeto es un singleton o no.

yfeldblum
fuente
2

Si por "clase estática" te refieres a una clase que solo tiene variables estáticas, entonces realmente pueden mantener el estado. Tengo entendido que la única diferencia sería cómo accedes a esto. Por ejemplo:

MySingleton().getInstance().doSomething();

versus

MySingleton.doSomething();

Los componentes internos de MySingleton obviamente serán diferentes entre ellos, pero, dejando de lado los problemas de seguridad de subprocesos, ambos funcionarán de la misma manera con respecto al código del cliente.

Programador fuera de la ley
fuente
2
Los singleton son en sí mismos objetos -> pueden pasarse como argumentos.
Christian Klauser
2

El patrón singleton se usa generalmente para dar servicio a datos estáticos o independientes de la instancia donde varios subprocesos pueden acceder a los datos al mismo tiempo. Un ejemplo pueden ser los códigos de estado.

Mayank
fuente
1

Los singleton nunca deben usarse (a menos que considere una clase sin estado mutable como singleton). Las "clases estáticas" no deberían tener un estado mutable, salvo quizás las memorias caché seguras para subprocesos y similares.

Prácticamente cualquier ejemplo de singleton muestra cómo no hacerlo.

Tom Hawtin - tackline
fuente
4
¿Qué pasa con las clases de administradores que controlan los recursos de hardware? ¿Qué pasa con las clases de archivos de registro?
RJFalconer
0

Si un singleton es algo de lo que puede deshacerse, para limpiarlo después, puede considerarlo cuando es un recurso limitado (es decir, solo 1) que no necesita todo el tiempo y tiene algún tipo de memoria o costo de los recursos cuando se asigna.

El código de limpieza se ve más natural cuando tiene un singleton, a diferencia de una clase estática que contiene campos de estado estáticos.

El código, sin embargo, lucirá similar de cualquier manera, así que si tienes razones más específicas para preguntar, quizás debas explicarlo.

Lasse V. Karlsen
fuente
0

Los dos pueden ser muy similares, pero recuerda que el verdadero Singleton tiene en sí una instancia (concedida, una vez) y luego se sirve. Una clase de base de datos PHP que devuelve una instancia de mysqlino es realmente un Singleton (como algunas personas lo llaman), porque está devolviendo una instancia de otra clase, no una instancia de la clase que tiene la instancia como miembro estático.

Por lo tanto, si está escribiendo una nueva clase de la que planea permitir solo una instancia en su código, también puede escribirla como Singleton. Piense en ello como escribir una clase simple-jane y agregarla para facilitar el requisito de instanciación única. Si está usando la clase de otra persona que no puede modificar (como mysqli), debería usar una clase estática (incluso si no puede prefijar su definición con la palabra clave).

Brian Warshaw
fuente
0

Los singleton son más flexibles, lo que puede ser útil en los casos en que desee que el método Instance devuelva diferentes subclases concretas del tipo Singleton en función de algún contexto.

nuevo dia
fuente
0

Las clases estáticas no se pueden pasar como argumentos; instancias de un singleton pueden ser. Como se mencionó en otras respuestas, esté atento a los problemas de subprocesos con clases estáticas.

rp

rp.
fuente
0

Un singleton puede tener un constructor y un destructor. Dependiendo de su idioma, el constructor puede llamarse automáticamente la primera vez que se usa su singleton, o nunca si su singleton no se usa en absoluto. Una clase estática no tendría tal inicialización automática.

Una vez que se obtiene una referencia a un objeto singleton, se puede usar como cualquier otro objeto. Es posible que el código del cliente ni siquiera necesite saber que está usando un singleton si una referencia al singleton se almacena anteriormente:

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

Obviamente, esto facilita las cosas cuando elige deshacerse del patrón Singleton en favor de un patrón real, como IoC.

Landon Kuhn
fuente
0

Utilice el patrón singleton cuando necesite calcular algo en tiempo de ejecución que calcularía en tiempo de compilación si pudiera, como tablas de búsqueda.

Jared Updike
fuente
0

Creo que un lugar donde Singleton tendrá más sentido que la clase estática es cuando tienes que construir un grupo de recursos costosos (como conexiones de bases de datos). No estaría interesado en crear el grupo si nadie los usa (la clase estática significa que usted hace el trabajo costoso cuando la clase está cargada).

Jagmal
fuente
0

Un singleton también es una buena idea si desea forzar un almacenamiento de datos en caché eficiente. por ejemplo, tengo una clase que busca definiciones en un documento xml. Dado que analizar el documento puede llevar un tiempo, configuro un caché de definiciones (utilizo SoftReferences para evitar outOfmemeoryErrors). Si la definición deseada no está en la caché, hago el costoso análisis xml. De lo contrario, devuelvo una copia del caché. Dado que tener múltiples cachés significaría que aún podría tener que cargar la misma definición varias veces, necesito tener un caché estático. Elijo implementar esta clase como singleton para poder escribir la clase usando solo miembros de datos normales (no estáticos). Esto me permite aún crear una diferenciación de la clase en caso de que la necesite por algún motivo (serialización, pruebas unitarias, etc.)

KitsuneYMG
fuente
0

Singleton es como un servicio, como ya se mencionó. Pro es su flexibilidad. Estático, bueno, necesita algunas partes estáticas para implementar Singleton.

Singleton tiene un código para encargarse de la creación de instancias del objeto real, lo que puede ser de gran ayuda si tiene problemas con las carreras. En una solución estática, es posible que deba lidiar con problemas de carreras en múltiples ubicaciones de código.

Sin embargo, al igual que Singleton se puede construir con algunas variables estáticas, es posible que pueda compararlo con 'goto'. Puede ser muy útil para construir otras estructuras, pero realmente necesita saber cómo usarlo y no debe "abusar" de él. Por lo tanto, la recomendación general es ceñirse a Singleton y usar estática si es necesario.

también verifique la otra publicación: ¿Por qué elegir una clase estática en lugar de una implementación singleton?

Amegon
fuente
0

referir esto

resumen:

a. Una regla general fácil que puede seguir es que si no necesita mantener el estado, puede usar una clase estática; de lo contrario, debe usar un Singleton.

segundo. use un Singleton si es un objeto particularmente "pesado". Si su objeto es grande y ocupa una cantidad razonable de memoria, muchas llamadas n / w (grupo de conexiones) ..etc. Para asegurarse de que no se instanciará varias veces. Una clase Singleton ayudará a evitar que este caso suceda.

Santh
fuente
-1

Cuando la clase única necesita estado. Los singleton mantienen un estado global, las clases estáticas no.

Por ejemplo, crear un ayudante para una clase de registro: si tiene una colmena modificable (usuario actual de HKey frente a máquina local de HKEY), puede ir:

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

Ahora, cualquier otra llamada a ese singleton operará en la colmena de la máquina local. De lo contrario, utilizando una clase estática, tendría que especificar esa colmena de máquina local en cada momento, o tener un método como ReadSubkeyFromLocalMachine.

David J. Sokol
fuente
1
Yo argumentaría en contra de usar un Singleton de esta manera ... Es muy peligroso mantener los estados persistentes, porque la próxima persona que llama podría olvidarse de configurar la colmena y escribir en el registro en la colmena incorrecta ... :-( Esto es probablemente un ejemplo de mal uso que hace que la gente piensa Singleton son malos.