2010-08-07 34 views
16

Recientemente tuve una entrevista y me preguntó sobre Singleton Design Patterns sobre cómo se implementan y le dije que usando variables estáticas y métodos estáticos podemos implementar Singleton Design Patterns.Java Singleton Design Pattern: Preguntas

Él parece ser un medio satisfecho con la respuesta, pero quiero saber

  1. ¿Cuántas maneras diferentes podemos aplicar diseño Singleton patrón en Java?
  2. ¿Cuál es el alcance de Singleton Object y cómo funciona realmente dentro de JVM? Sé que siempre tendríamos una instancia de Singleton Object, pero ¿cuál es el alcance real de ese objeto, está en JVM o si hay varias aplicaciones ejecutándose de acuerdo a su contexto dentro de la JVM, estaba realmente perplejo al respecto y no pudo dar una explicación satisfactoria?
  3. Por último, preguntó si es posible usar el objeto Singleton con clústeres con una explicación y ¿hay alguna manera de que Spring no implemente el patrón de diseño Singleton cuando hacemos una llamada a Bean Factory para obtener los objetos?

Cualquier entrada sería muy apreciada por Singleton y ¿cuáles son las principales cosas a tener en cuenta al tratar con Singletons?

Gracias.

+0

Creo que la razón por la que estaba medio satisfecho es que el punto de un conjunto unitario es ** ** sustituir una clase de métodos estáticos con una llena de métodos de instancia, y una única instancia almacenada en un campo estático. –

+0

@Kirk Woll - ¿Puede explicar la explicación, quiero entenderlo mejor? – Rachel

+5

Digamos que comienzas con una clase con solo métodos estáticos. Si desea convertir esto en un singleton, eliminará el modificador ** static ** de todos sus métodos. Además, agregará un campo estático cuyo tipo sea el mismo que el de su clase para contener la instancia solitaria. Entonces, mi punto es que los métodos estáticos y los singleton son dos soluciones mutuamente excluyentes para el mismo problema. Por lo tanto, sugerir el uso de métodos estáticos no es realmente correcto para implementar un singleton. –

Respuesta

14

Hay algunas maneras de implementar un patrón Singleton en Java:

// private constructor, public static instance 
// usage: Blah.INSTANCE.someMethod(); 
public class Blah { 
    public static final Blah INSTANCE = new Blah(); 
    private Blah() { 
    } 
    // public methods 
} 

// private constructor, public instance method 
// usage: Woo.getInstance().someMethod(); 
public class Woo { 
    private static final Woo INSTANCE = new Woo(); 
    private Woo() { 
    } 
    public static Woo getInstance() { 
     return INSTANCE; 
    } 
    // public methods 
} 

// Java5+ single element enumeration (preferred approach) 
// usage: Zing.INSTANCE.someMethod(); 
public enum Zing { 
    INSTANCE; 
    // public methods 
} 

Dados los ejemplos anteriores, tendrá una única instancia por cargador de clases.

En relación con el uso de un singleton en un clúster ... No estoy seguro de cuál es la definición de "usar" ... ¿implica el entrevistador que se crea una única instancia en todo el clúster? No estoy seguro si eso tiene mucho sentido ...?

Por último, la definición de un objeto no único en primavera se realiza simplemente a través del atributo singleton = "false".

+1

+1 para explicar las diferentes formas de crear singletons – Rachel

+0

Como referencia, el patrón Singleton incluye un constructor * protected *. Algo sobre poder subclasificar/heredar/extender un singleton, como si eso no fuera propenso a desastres. – cHao

+0

¿No deberías '@ Anular' el método Clone? : -/ – st0le

1

Singleton se implementa comúnmente al tener un objeto de instancia estático (private SingletonType SingletonType.instance) que se instancia de forma perezosa a través de un método estático SingletonType SingletonType.getInstance(). Hay muchas dificultades para usar singletons, tantos, de hecho, que muchos consideran singleton como un diseño anti patrón. Dadas las preguntas sobre Spring, el entrevistador probablemente buscaba una comprensión no solo de los singleton, sino también de sus dificultades, así como una solución alternativa para estas trampas conocida como inyección de dependencia. Puede encontrar el video en la página Google Guice particularmente útil para comprender las dificultades de los singleton y cómo DI resuelve esto.

+1

¿Puede dar un ejemplo que muestre cuáles son las dificultades y cómo DI lo aborda, si esto está fuera de alcance aquí, ¿puede proporcionar algunos consejos para ello? – Rachel

0

un campo estático puede tener varias ocurrencias en una JVM: al usar cargadores de clases diferentes, la misma clase se puede cargar e inicializar varias veces, pero cada una vive aislada y JVM trata las clases cargadas como clases completamente diferentes.

No creo que a un programador de Java le importe, a menos que esté escribiendo algunos frameworks. "Uno por VM" es una buena respuesta. La gente a menudo habla de esa manera, mientras que, hablando en sentido estricto, dicen "uno por cargador de clases".

¿Podemos tener un singleton por clúster? Bueno, eso es un juego de conceptos. No agradecería que un entrevistador lo diga de esa manera.

0
  1. Existe la forma estándar, que ya ha cubierto. Además, la mayoría de los esquemas de inyección de dependencia tienen alguna manera de marcar una clase como singleton; De esta manera, la clase se parece a cualquier otra, pero el framework se asegura de que cuando se inyectan instancias de esa clase, siempre sea la misma instancia.

  2. Ahí es donde se pone peluda. Por ejemplo, si la clase se inicializa dentro de un contexto de aplicación Tomcat, la duración de la instancia singleton está ligada a ese contexto. Pero puede ser difícil predecir dónde se inicializarán tus clases; así que es mejor no hacer suposiciones. Si desea asegurarse de que hay exactamente una instancia por contexto, debe vincularlo como un atributo de ServletContext. (O deje que un marco de inyección de dependencia se encargue de eso.)

  3. -

  4. No estoy seguro de entender la pregunta - pero si estamos hablando acerca de tener una instancia singleton que es compartida entre varios nodos del clúster, entonces creo EJB hace esto posible (por medio de control remoto frijoles), aunque nunca lo he probado. No tengo idea de cómo lo hace Spring.

2

No estoy de acuerdo con @irreputable.

El alcance de un Singleton es su nodo en el árbol de Classloader. Su cargador de clases contenedor y cualquier cargador de clases hijo puede ver el Singleton.

Es importante entender este concepto de alcance, especialmente en los servidores de aplicaciones que tienen intrincadas jerarquías de Classloader.

Por ejemplo, si tiene una biblioteca en un archivo jar en el classpath del sistema de un servidor de aplicaciones, y esa biblioteca usa un Singleton, ese Singleton (probablemente) será el mismo para cada "aplicación" implementada en al servidor de la aplicación. Eso puede o no ser algo bueno (depende de la biblioteca).

Los cargadores de clases son, en mi humilde opinión, uno de los conceptos más importantes en Java y JVM, y los Singleton juegan directamente en eso, así que creo que es importante que un programador Java "se preocupe".

+0

Diría que es culpa de los servidores de aplicaciones que los desarrolladores estén expuestos a estos problemas de carga de clases. Y creo que es mejor tener un proceso por aplicación. – irreputable

+0

En lugar de un proceso por aplicación: OSGi. – harschware

+0

IIRC: Java EE recomienda tener cargadores de clases que intenten usar sus propias clases antes de delegar en el principal. Java SE prohíbe esto. –

1

3: Por último, preguntó si es posible usar objetos Singleton con clústeres con explicación y ¿hay alguna manera de que Spring no implemente el patrón de diseño Singleton cuando hacemos una llamada a Bean Factory para obtener los objetos?

La primera parte de esta pregunta es difícil de responder sin un contexto tecnológico. Si la plataforma del clúster incluye la capacidad de realizar llamadas a objetos remotos como si fueran objetos locales (por ejemplo, como es posible con los EJB que usan RMI o IIOP bajo el capó), entonces sí se puede hacer. Por ejemplo, los objetos singleton residentes de JVM podrían ser proxies para un objeto singleton de todo el clúster, que se localizó/cableó inicialmente a través de JNDI o algo así. Pero los singletons en todo el clúster son un cuello de botella potencial porque cada llamada en uno de los proxys singleton da como resultado un RPC (costoso) a un solo objeto remoto.

La segunda parte de la pregunta es que Spring Bean Factories se puede configurar con diferentes ámbitos. El valor predeterminado es para singletons (con ámbito en el nivel de webapp), pero también pueden ser de sesión o solicitud de ámbito, o una aplicación puede definir su propio mecanismo de ámbito.

+0

Para Spring Bean Framework, ¿de alguna manera es posible obtener múltiples instancias de un Bean en lugar de obtener solo una instancia de Spring Bean que es por defecto para Spring? – Rachel

+0

@Rachel - eso es lo que dije. Los detalles están en la documentación de Spring. –

+0

+1 para explicar el mecanismo de clúster para Singletons y EJB Approach. – Rachel

2

Me resulta difícil creer que tantas respuestas pasaron por alto la mejor práctica estándar para singletons - usando Enums - esto le dará un singleton cuyo alcance es el cargador de clases que es lo suficientemente bueno para la mayoría de los propósitos.

public enum Singleton { ONE_AND_ONLY_ONE ; ... members and other junk ... } 

En cuanto a embarazos únicos en los niveles superiores - tal vez estoy siendo tonta - pero mi inclinación sería distribuir la propia máquina virtual Java (y restringir los cargadores de clases). Entonces la enumeración sería adecuada para el trabajo.

+4

Psh. La * mejor * práctica estándar para singletons es evitarlos si es posible. Y es * siempre * posible a nivel de aplicación. Su necesidad no es tan grande como lo sugieren los mil millones de personas que aprendieron sobre el patrón de Singleton y estaban encantados con la capacidad de usar una variable global glorificada. – cHao

+0

Encajado. los singletons no son más que variables globales. – emory

+0

De hecho, Globaltons. Creo que el enfoque 'enum' es simplemente extraño. No usamos un 'enum' vacío para clases de métodos estáticos. OTOH, usando 'enum', los resalta como extraños. –

0

Singleton es un patrón creado y, por lo tanto, rige la instanciación de objetos. La creación de singletons obligaría a renunciar voluntaria o involuntariamente al control sobre la creación del objeto y, en su lugar, confiar en alguna forma de obtener acceso a él.

Esto se puede lograr utilizando métodos estáticos o mediante inyección de dependencia o utilizando el patrón de fábrica. El medio es inmaterial. En el caso del enfoque del constructor protegido normal(), el consumidor necesariamente necesita usar el método estático para acceder al singleton. En el caso de DI, el consumidor voluntariamente cede el control sobre la instanciación de la clase y en su lugar se basa en un marco DI para inyectar la instancia en sí mismo.

Como señalan otros carteles, el cargador de clases en Java definiría el alcance del singleton. Los singletons en clusters generalmente no son "instancias únicas" sino una colección de instancias que muestran un comportamiento similar. Estos pueden ser componentes en SOA.

0

el siguiente código es de here

El punto clave es que debe Override el método clone ... La Wikipedia example también es útil.

public class SingletonObject 
{ 
    private SingletonObject() 
    { 
    // no code req'd 
    } 

    public static SingletonObject getSingletonObject() 
    { 
    if (ref == null) 
     // it's ok, we can call this constructor 
     ref = new SingletonObject();   
    return ref; 
    } 

    public Object clone() 
    throws CloneNotSupportedException 
    { 
    throw new CloneNotSupportedException(); 
    // that'll teach 'em 
    } 

    private static SingletonObject ref; 
} 
0

Query 1:

Diferentes formas de crear Singleton

  1. Normal Singleton: inicialización estática
  2. ENUM
  3. Lazy Singleton: Doble bloqueo Singleton &: inicialización-en-demand_holder_idiom singleton

Tener un vistazo a continuación Código:

public final class Singleton{ 
    private static final Singleton instance = new Singleton(); 

    public static Singleton getInstance(){ 
     return instance; 
    } 
    public enum EnumSingleton { 
     INSTANCE; 
    } 
    public static void main(String args[]){ 
     System.out.println("Singleton:"+Singleton.getInstance()); 
     System.out.println("Enum.."+EnumSingleton.INSTANCE); 
     System.out.println("Lazy.."+LazySingleton.getInstance()); 
    } 
} 
final class LazySingleton { 
    private LazySingleton() {} 
    public static LazySingleton getInstance() { 
     return LazyHolder.INSTANCE; 
    } 
    private static class LazyHolder { 
     private static final LazySingleton INSTANCE = new LazySingleton(); 
    } 
} 

SE relacionada preguntas:

What is an efficient way to implement a singleton pattern in Java?

Query 2:

Una instancia Singleton se crea por ClassLoader. Si desea evitar la creación del objeto Singleton durante Serializaiton, anule el siguiente método y devuelva la misma instancia.

private Object readResolve() { 
    return instance; 
} 

Consulta 3:

para lograr un nivel de clúster Singleton entre varios servidores, almacenar este objeto Singleton en un caches distribuidas como Terracotta, Coherence etc.

0

Singleton es un patrón de diseño creacional.

intenciones del patrón de diseño Singleton:

  • asegurar una clase tiene sólo una instancia, y proporcionar una perspectiva global acceso a ella.
  • "Inicialización just-in-time" encapsulada o "inicialización en el primer uso de ".

Estoy mostrando tres tipos de implementación aquí.

  1. Justo a tiempo de inicialización (Asigna memoria durante la primera ejecución, incluso si usted no lo utiliza)

    class Foo{ 
    
        // Initialized in first run 
        private static Foo INSTANCE = new Foo(); 
    
        /** 
        * Private constructor prevents instantiation from outside 
        */ 
        private Foo() {} 
    
        public static Foo getInstance(){ 
         return INSTANCE; 
        } 
    
    } 
    
  2. de inicialización en el primer uso (o inicialización perezosa)

    class Bar{ 
    
        private static Bar instance; 
    
        /** 
        * Private constructor prevents instantiation from outside 
        */ 
        private Bar() {} 
    
        public static Bar getInstance(){ 
    
         if (instance == null){ 
          // initialized in first call of getInstance() 
          instance = new Bar(); 
         } 
    
         return instance; 
        } 
    } 
    
  3. Este es otro estilo de inicialización Lazy, pero la ventaja es que esta solución es segura para subprocesos sin requiri ng construcciones de lenguaje especial (es decir volátil o sincronizado). Ver más en SourceMaking.com

    class Blaa{ 
    
        /** 
        * Private constructor prevents instantiation from outside 
        */ 
        private Blaa() {} 
    
        /** 
        * BlaaHolder is loaded on the first execution of Blaa.getInstance() 
        * or the first access to SingletonHolder.INSTANCE, not before. 
        */ 
        private static class BlaaHolder{ 
         public static Blaa INSTANCE = new Blaa(); 
        } 
    
        public static Blaa getInstance(){ 
         return BlaaHolder.INSTANCE; 
        } 
    
    }