2011-12-22 22 views

Respuesta

19

Crear una enumeración con una instancia

enum Singleton { 
    INSTANCE; 

    private Field field = VALUE; 
    public Value method(Arg arg) { /* some code */ } 
} 

// You can use 
Value v = Singleton.INSTANCE.method(arg); 

EDIT: El Java Enum Tutorial muestra cómo agregar campos y métodos para una enumeración.


Por cierto: A menudo, cuando se puede utilizar un Singleton, que realmente no necesita una clase de utilidad que va a hacer lo mismo. La versión aún más corta es solo

enum Utility {; 
    private static Field field = VALUE; 
    public static Value method(Arg arg) { /* some code */ } 
} 

// You can use 
Value v = Utility.method(arg); 

Donde los Singletons son útiles es cuando implementan una interfaz. Esto es especialmente útil para probar cuando usa inyección de Dependencia. (Una de las debilidades de usar un Singleton o sustitución de clase de utilidad en pruebas unitarias)

p.

interface TimeService { 
    public long currentTimeMS(); 
} 

// used when running the program in production. 
enum VanillaTimeService implements TimeService { 
    INSTANCE; 
    public long currentTimeMS() { return System.currentTimeMS(); } 
} 

// used in testing. 
class FixedTimeService implements TimeService { 
    private long currentTimeMS = 0; 
    public void currentTimeMS(long currentTimeMS) { this.currentTimeMS = currentTimeMS; } 
    public long currentTimeMS() { return currentTimeMS; } 
} 

Como se puede ver, si su código utiliza servidor de tiempos en todas partes, se puede inyectar o bien el VanillaTimeService.INSTANCE o una new FixedTimeService() donde se puede controlar el tiempo de forma externa es decir, sus marcas de tiempo será el mismo cada vez que se ejecuta la prueba.

En resumen, si no necesita su singleton para implementar una interfaz, todo lo que necesita es una clase de utilidad.

+0

@Pater Gracias por la rápida respuesta –

+0

No lo entiendo ... no se puede llamar a ningún método en su singleton –

+0

@remi bourgarel un enum de Java es solo una clase. Simplemente agregue las variables, los métodos y un constructor a Singleton enum (después de la declaración de INSTANCE) como lo haría con cualquier otra clase y INSTANCE los tiene. – josefx

1

Sigue la receta de Joshua Bloch enum en "Effective Java" 2nd edition. Esa es la mejor manera de crear un singleton.

No entiendo por qué esto sube tanto. ¿No es singleton un patrón de diseño desacreditado? El GoF lo votaría fuera de la isla hoy.

1

Puede usar uno de los contenedores IoC (por ejemplo, Google Guice) y usar su clase como singleton (ansioso o flojo, depende de sus necesidades). Es fácil y flexible ya que la creación de instancias está controlada por IoC framework; no necesita ningún cambio de código si, por ejemplo, decide hacer que su clase no sea singleton más tarde.

+0

En el contexto de una pregunta de una entrevista, no es una buena idea resolver pequeños problemas como ese mediante la introducción de grandes marcos como un contenedor IoC. –

+0

¿Por qué? IoC es algo bastante común ahora. Y es una ventaja si el entrevistado lo sabe y propone usar el marco de trabajo de IoC como una de las posibles soluciones. – Artem

+0

Sí, IoC es un conocimiento común hoy en día. Por mucho, no se usa en todos y cada uno de los proyectos. Entonces, a menos que el entrevistador mostrara interés en cualquier marco de trabajo de IoC antes, _I_ supondría que la pregunta quiere poner a prueba el conocimiento sobre el lenguaje en sí mismo. Si no demuestras que sabes cuán simples se pueden hacer las cosas de una manera simple pero solo de una manera complicada que involucre varios frameworks pesados, entonces se puede suponer que tu habilidad normal para resolver problemas funciona de la misma manera.
Lo mejor que se puede hacer: mostrar ambas soluciones. –

8
public class Singleton { 
    public static final Singleton instance = new Singleton(); 
    private Singleton() {} 
    public void foo() {} 
} 

a continuación, utilizar

Singleton.instance.foo(); 
+1

Para completar: por favor agregue un constructor no-arg privado. –

+0

¡Genial! Gracias A.H.! (Mi error habitual :) – andrey

0

utilizar un generador de objetos, ir a buscar el objeto único de esta fábrica.

ObjectFactory factory; 
.... 
MySingletonObject obj = factory.getInstance(MySingletonObject.class); 

Por supuesto, hay muchos marcos para ayudarle a lograr esto. el marco de primavera es una opción popular.

+0

¿No está la fábrica usando un método estático? Eso es algo que él no quiere. – Eduard

0

Desde dentro del constructor necesitas controlar si ya hay una instancia de la clase en alguna parte. Por lo tanto, debe almacenar la referencia a su instancia singleton en una variable o clase estática. Luego, en contructor of singleton siempre verificaría si existe una instancia de clase singleton. Si es así, no haría nada si no fuera así, lo crearía y establecería una referencia.

2

Otro enfoque es el singleton holder idiom que ofrece la inicialización de la demanda:

public class Something { 
     private Something() { 
     } 

     private static class LazyHolder { 
       public static final Something INSTANCE = new Something(); 
     } 

     public Something getInstance() { 
       return LazyHolder.INSTANCE; 
     } 
} 

(ejemplo modificado, el método getInstance hecho no estática)

Tenga en cuenta que únicos independientes de este tipo deben evitarse siempre que sea posible, ya que promueve estado global, conduce a un código difícil de probar y depende de un solo contexto de cargador de clases para nombrar algunos posibles inconvenientes.

Cuestiones relacionadas