2010-02-17 8 views
28

¿Cuál es la mejor manera de diseñar una clase singleton que podría arrojar una excepción?Singleton y Excepción

Aquí tengo un Singleton (usando el método de Bill Pugh, documentado en Wiki para Singleton).

private static class SingletonObjectFactoryHolder{ 
    //1 
     private static final ObjectFactory INSTANCE = new ObjectFactory(); 
    } 

    private ObjectFactory() throws Exception{ 
    //2 
      //create the factory 
    } 


    public static ObjectFactory getInstance(){ 
    //3 
     return SingletonObjectFactoryHolder.INSTANCE; 
    } 

Si se produce una excepción a los 2, me gustaría propagarla a la persona que llama. Sin embargo, no puedo lanzar una excepción desde la línea 1.

Entonces, ¿es mi única opción devolver un objeto nulo si el objeto singleton no se creó correctamente?

Gracias

P.S Soy consciente de que este Singleton puede romperse si su carga a través de diferentes cargadores de clases o si se carga un acto reflejo, pero es lo suficientemente bueno para mi propósito.

// ACTUALIZACIÓN

Soy curioso, ¿no puedo reorganizar mi diseño de la siguiente manera a lanzar excepciones?

Además, no necesito ninguna sincronización (el cargador de clases garantiza que la clase interna estática solo se cargue una vez y solo cuando se llame a getInstance()). Por lo tanto, hilo-seguro y lazily-instanciado?

private static class SingletonObjectFactoryHolder{ 
     //1 
      public static ObjectFactory getInstance() throws Exception{ 
     return new ObjectFactory(); 
      } 
} 

private ObjectFactory() throws Exception{ 
     //2 
     //create the factory 
} 


public static ObjectFactory getInstance(){ 
     //3 
    return SingletonObjectFactoryHolder.getInstance(); 
} 

Gracias de nuevo.

+1

La respuesta de BalusC es correcta, pero vea también http://www.yoda.arachsys.com/csharp/singleton.html – finnw

+0

Gracias. Aunque se siente un poco inusual lanzar un error. :) – CaptainHastings

+0

@finnw versión actualizada del enlace: http://csharpindepth.com/Articles/General/Singleton.aspx –

Respuesta

34

Utilice un inicializador estático y volver a lanzar el Exception como ExceptionInInitializerError. Haga clic en el enlace para leer el Javadoc, verá que se adapta exactamente a este requisito funcional en particular: manejo de excepciones durante la inicialización estática . Un singleton es, en realidad, nada menos que un objeto global inicializado de forma estática y perezosa.

private static class SingletonObjectFactoryHolder{ 
    private static final ObjectFactory INSTANCE; 
    static { 
     try { 
      INSTANCE = new ObjectFactory(); 
     } catch (Exception e) { 
      throw new ExceptionInInitializerError(e); 
     } 
    } 
} 

No hay necesidad de double checked locking modismo que se considera un anti-patrón y en algunas circunstancias, incluso inseguros.

+3

(+1) Gracias por enseñarme acerca de EIIE – harschware

+0

@BalusC no es más fácil crear la instancia en el interior un constructor privado y manejar la excepción allí? – oldergod

+0

@oldergod: me pregunto cómo piensa crear una instancia en el constructor de la instancia sin ejecutar un ciclo infinito creando múltiples instancias, violando el patrón singleton. Además, OP mencionó explícitamente el uso del método de Bill Pugh, así que continué con ese método. – BalusC

0

Simplemente no arroje una excepción desde el constructor del objeto. Puede proporcionar el método init() y lanzar su excepción desde allí si es necesario.

0

Puede comprobar la INSTANCIA nula dentro de getInstance, e inicializarla perezosamente. Pero por lo general es mejor si los constructores no lanzan, si puede hacer que el constructor sea más seguro que probablemente sea el mejor.

-1

Estoy de acuerdo con Arne Burmeister, el código para que se vería así:

private static class SingletonObjectFactoryHolder 
{ 
    private static ObjectFactory INSTANCE; 


    private ObjectFactory() 
    { 

    } 

    public static String getInstance() throws Exception 
    { 
     return (INSTANCE == null) ? (INSTANCE = new ObjectFactory()) : INSTANCE; 
    // A ternary operator might not be the best fit if you need to throw an exception, but I think it looks nicer than the if(INSTANCE==null){} else{} for lazy instantiation. 
    } 

}