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

StackOverflow https://stackoverflow.com/questions/46541

  •  09-06-2019
  •  | 
  •  

Pregunta

Nombre las consideraciones de diseño al decidir entre el uso de un único versus una clase estática.Al hacer esto, te ves obligado a contrastar los dos, por lo que cualquier contraste que se te ocurra también será útil para mostrar tu proceso de pensamiento.Además, a todo entrevistador le gusta ver ejemplos ilustrativos.:)

¿Fue útil?

Solución

  • Los singleton pueden implementar interfaces y heredar de otras clases.
  • Los singleton se pueden cargar de forma diferida.Sólo cuando realmente sea necesario.Esto es muy útil si la inicialización incluye costosas cargas de recursos o conexiones a bases de datos.
  • Los singleton ofrecen un objeto real.
  • Los singleton se pueden ampliar a una fábrica.La gestión de objetos detrás de escena es abstracta, por lo que es más fácil de mantener y da como resultado un mejor código.

Otros consejos

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

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

En lugar de eso, mira en Inyección de dependencia y Inversión del contenedor de control bibliotecas.Varias de las bibliotecas de IoC se encargarán de la gestión de por vida por usted.

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

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


EDITAR:La brigada de enterrar vino de excavar...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.

Una de mis discusiones favoritas sobre este tema es aquí (sitio original inactivo, ahora vinculado a Archivo de Internet 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.

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á SÓLO en el caso.

Por lo tanto, el singleton se puede modificar más adelante para realizar agrupaciones, instancias locales de subprocesos, etc.Y no es necesario cambiar ninguno de los códigos ya escritos 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ás uno de ellos...hasta que no lo hagas.

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

Piense en un singleton como un servicio.Es un objeto que proporciona un conjunto específico de funcionalidades.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 quizás quieras 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 funciones que se pueden aplicar en cualquier lugar.El objeto de fábrica singleton es un tipo específico de objeto con una responsabilidad clara que se puede crear y transmitir cuando sea necesario.

Se crean instancias de clases estáticas en tiempo de ejecución.Esto podría llevar mucho tiempo.Solo se pueden crear instancias de singleton cuando sea necesario.

Los singleton 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 realmente deberías 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 tratarlo como simplemente un objeto.

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

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

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

versus

MySingleton.doSomething();

Las partes internas de MySingleton obviamente serán diferentes entre ellos pero, dejando de lado los problemas de seguridad de subprocesos, ambos funcionarán igual con respecto al código del cliente.

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

Nunca se deben utilizar singletons (a menos que considere una clase sin estado mutable como singleton).Las "clases estáticas" no deberían tener ningún estado mutable, excepto quizás cachés seguros para subprocesos y similares.

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

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

El código de limpieza parece 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, se verá más o menos igual en ambos sentidos, por lo que si tiene razones más específicas para preguntar, tal vez debería dar más detalles.

Los dos pueden ser bastante similares, pero recuerde que el verdadero Singleton debe sí mismo ser instanciado (otorgado, una vez) y luego servido.Una clase de base de datos PHP que devuelve una instancia de mysqli no es realmente un Singleton (como lo llaman algunas personas), porque devuelve 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 y agregarle para facilitar el requisito de instanciación única.Si estás usando la clase de otra persona que no puedes modificar (como mysqli), debería utilizar una clase estática (incluso si no antepone su definición con la palabra clave).

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

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

rp

Un singleton puede tener un constructor y un destructor.Dependiendo de su idioma, el constructor puede ser llamado 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 utilizar como cualquier otro objeto.Es posible que el código del cliente ni siquiera necesite saber que está utilizando un singleton si se almacena una referencia al singleton anteriormente:

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

Obviamente, esto facilita las cosas cuando eliges abandonar el patrón Singleton en favor de un patrón real, como IoC.

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

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

Un singleton también es una buena idea si desea forzar un almacenamiento en caché eficiente de los datos.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 (uso SoftReferences para evitar outOfmemeoryErrors).Si la definición deseada no está en el caché, hago el costoso análisis xml.De lo contrario, devuelvo una copia del caché.Dado que tener varios cachés significaría que aún tendría que cargar la misma definición varias veces, necesito tener un caché estático.Elijo implementar esta clase como un singleton para poder escribir la clase usando solo miembros de datos normales (no estáticos).Esto me permite seguir creando una instanciación de la clase si la necesito por algún motivo (serialización, pruebas unitarias, etc.)

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

Singleton tiene código para encargarse de la creación de instancias del objeto real, lo que puede ser de gran ayuda si tienes problemas de carrera.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 puedas compararlo con 'goto'.Puede ser muy útil para construir otras estructuras, pero realmente necesitas saber cómo usarlo y no debes "usarlo en exceso".Por lo tanto, la recomendación general es seguir con Singleton y usar estática si es necesario.

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

referirse este

resumen:

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

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

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

Por ejemplo, crear una ayuda para una clase de registro:Si tiene una colmena modificable (usuario actual de HKey vs.HKEY Local Machine) podrías ir:

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

Ahora, cualquier llamada adicional a ese singleton funcionará en la colmena de la máquina local.De lo contrario, al usar una clase estática, tendría que especificar esa sección de Máquina local cada vez, o tener un método como ReadSubkeyFromLocalMachine.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top