¿Cuál es la diferencia entre un patrón de Singleton y una clase estática en Java?

¿Cómo se diferencia un singleton de una clase con solo campos estáticos?

Casi cada vez que escribo una clase estática, termino deseando haberlo implementado como una clase no estática. Considerar:

  • Una clase no estática se puede extender. El polymorphism puede ahorrar mucha repetición.
  • Una clase no estática puede implementar una interfaz, que puede ser útil cuando desee separar la implementación de la API.

Debido a estos dos puntos, las clases no estáticas permiten escribir pruebas unitarias más confiables para los elementos que dependen de ellos, entre otras cosas.

Sin embargo, un patrón singleton está solo a medio paso de las clases estáticas. En cierto modo, obtiene estos beneficios, pero si accede a ellos directamente dentro de otras clases a través de `ClassName.Instance ‘, está creando un obstáculo para acceder a estos beneficios. Al igual que ph0enix señaló, es mucho mejor utilizar un patrón de dependency injection. De esta forma, se puede decir a un marco DI que una clase en particular es (o no es) un singleton. Obtienes todos los beneficios de la burla, las pruebas unitarias, el polymorphism y mucha más flexibilidad.

Vamos a resumir 🙂

La diferencia esencial es: la forma de existencia de un singleton es un objeto, estático no lo es. Esto condujo a las siguientes cosas:

  • Singleton se puede extender. Estático no.
  • La creación de Singleton puede no ser segura en caso de subprocesos si no se implementa correctamente. Estático no.
  • Singleton se puede pasar como un objeto. Estático no.
  • Singleton puede ser basura recolectada. Estático no.
  • ¡Singleton es mejor que la clase estática!
  • Más aquí pero aún no me he dado cuenta 🙂

Por último, pero no menos importante, cada vez que implementes un singleton, considera rediseñar tu idea para no usar este objeto de Dios (créeme, tenderás a poner todas las cosas “interesantes” en esta clase) y usarás una clase normal llamado “Contexto” o algo así en su lugar.

Un singleton se puede inicializar perezosamente, por ejemplo.

La diferencia es independiente del lenguaje. Singleton es por definición: “Asegúrese de que una clase tenga solo una instancia y proporcione un punto de acceso global a ella.” Una clase llena de solo campos estáticos no es igual a singleton, pero tal vez en su escenario de uso brinden la misma funcionalidad. Pero como JRL dijo que la iniciación perezosa es una diferencia.

Creo que lo significativo es ‘objeto’ en la progtwigción orientada a objetos. Excepto en algunos casos, deberíamos restringirnos al uso de clases estáticas. Que los casos son:

  1. Cuando crear un objeto no tiene sentido. Me gusta los métodos de java.lang.Math . Podemos usar la clase como un objeto. Porque el comportamiento de los métodos de clase matemática no depende del estado de los objetos que se crearán en esta clase.
  2. Los códigos que se utilizarán conjuntamente por más de un método de objeto, los códigos que no alcanzan las variables del objeto y que probablemente se cerrarán pueden ser métodos estáticos

Otra cosa importante es singleton es extensible. Singleton se puede extender. En la clase de Matemáticas , utilizando los métodos finales, se ha evitado la creación y extensión del objeto de esta clase. Lo mismo es cierto para la clase java.lang.System . Sin embargo, la clase Runtime es un único objeto, no un método estático. En este caso, puede anular los métodos de herencia de la clase Runtime para diferentes propósitos.

Puede retrasar la creación de un objeto Singleton hasta que sea necesario (carga diferida) . Sin embargo, para las clases de métodos estáticos, no existe una condición. Si llega a cualquier miembro estático de la clase, la clase se cargará en la memoria.

Como resultado, el beneficio más básico para la clase de método estático es que no tiene que crear un objeto, pero cuando se usa incorrectamente, eliminará que su código esté orientado a objetos.

Al menos puede reemplazarlo más fácilmente por un simulacro o un talón para pruebas unitarias. Pero no soy un gran admirador de los singleton por exactamente la razón que estás describiendo: son variables globales disfrazadas.

Una clase singleton tendrá una instancia que generalmente es una y solo una por cargador de clases. Por lo tanto, puede tener métodos regulares (no estáticos) y se pueden invocar en esa instancia particular.

Si bien es una clase con solo métodos estáticos, en realidad no es necesario crear una instancia (por esta razón, la mayoría de las personas / frameworks hacen que este tipo de clases de Util sean abstractas). Simplemente invocará los métodos en clase directamente.

Un singleton es una clase con solo una instancia, forzada. Esa clase puede tener estado (sí sé que las variables estáticas mantienen el estado), no todas las variables o métodos miembros deben ser estáticos.

Una variación sería un pequeño conjunto de estos objetos, lo que sería imposible si todos los métodos fueran estáticos.

Lo primero que se le viene a la mente es que si desea usar una clase con solo métodos y atributos estáticos en lugar de un singleton, deberá usar el inicializador estático para inicializar correctamente ciertos atributos. Ejemplo:

 class NoSingleton { static { //initialize foo with something complex that can't be done otherwise } static private foo; } 

Esto se ejecutará en el tiempo de carga de la clase, que probablemente no sea lo que usted desea. Usted tiene más control sobre este shebang completo si lo implementa como singleton. Sin embargo, creo que usar singletons no es una buena idea en ningún caso.

NOTA: Los ejemplos están en C #, ya que eso es con lo que estoy más familiarizado, pero el concepto debería aplicarse a Java de la misma manera.

Ignorando el debate sobre cuándo es apropiado usar objetos Singleton, una diferencia principal de la que soy consciente es que un objeto Singleton tiene una instancia que puede pasar.

Si usa una clase estática, se conecta estrictamente a una implementación particular, y no hay forma de alterar su comportamiento en tiempo de ejecución.

Diseño pobre usando clase estática:

 public class MyClass { public void SomeMethod(string filename) { if (File.Exists(filename)) // do something } } 

Alternativamente, podrías hacer que tu constructor tome una instancia de una interfaz particular. En producción, podría usar una implementación de Singleton de esa interfaz, pero en las pruebas unitarias, simplemente puede burlarse de la interfaz y alterar su comportamiento para satisfacer sus necesidades (haciendo que arroje alguna excepción oscura, por ejemplo).

 public class MyClass { private IFileSystem m_fileSystem; public MyClass(IFileSystem fileSystem) { m_fileSystem = fileSystem; } public void SomeMethod(string filename) { if (m_fileSystem.FileExists(filename)) // do something } } 

Esto no quiere decir que las clases estáticas sean SIEMPRE malas, simplemente no es un buen candidato para cosas como sistemas de archivos, conexiones de bases de datos y otras dependencias de capa inferior.

Una de las principales ventajas de los singleton es que puede implementar interfaces y heredar de otras clases. A veces tiene un grupo de singletons que proporcionan una funcionalidad similar en la que desea implementar una interfaz común, pero son responsables de un recurso diferente.

Singleton Class: Singleton Class es una clase de la cual solo puede existir una sola instancia por classloader.

Helper Class (clase con solo campos / métodos estáticos): no existe ninguna instancia de esta clase. Solo se puede acceder directamente a los campos y métodos como constantes o métodos auxiliares.

Estas pocas líneas de este blog lo describen muy bien:

En primer lugar, el patrón Singleton es muy útil si desea crear una instancia de una clase. Para mi clase de ayuda no queremos realmente instanciar ninguna copia de la clase. La razón por la que no deberías usar una clase Singleton es porque para esta clase de ayuda no usamos ninguna variable. La clase singleton sería útil si contuviera un conjunto de variables de las que solo quisiéramos un conjunto y los métodos usaran esas variables, pero en nuestra clase de ayuda no utilizamos ninguna variable aparte de las pasadas (que hacemos finales) . Por esta razón, no creo que deseemos una instancia singleton porque no queremos ninguna variable y no queremos que nadie esté instantaneando esta clase. Entonces, si no quieres que nadie crea una instancia de la clase, que normalmente es si tienes algún tipo de clase auxiliar / utilitaria, entonces utilizo la que yo llamo la clase estática, una clase con un constructor privado y solo consiste en métodos estáticos sin ningún cualquier variable