2010-02-17 18 views
28

Jaki jest najlepszy sposób zaprojektowania klasy singleton, która może rzucić wyjątek?Singleton i wyjątek

Tutaj mam Singleton (używając metody Billa Pugha, udokumentowanej na Wiki dla 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; 
    } 

Jeśli w punkcie 2 zostanie zgłoszony wyjątek, chcę go przekazać rozmówcy. Jednak nie mogę rzucić wyjątku od linii 1.

Czy moja jedyna opcja zwraca obiekt zerowy, jeśli obiekt singleton nie został poprawnie utworzony?

Dzięki

P.S Zdaję sobie sprawę, że to Singleton może złamać jeśli jego ładowane poprzez różne classloaders czy załadowany odruchowo, ale jest wystarczająco dobre dla mojego celu.

// UPDATE

Ciekaw jestem, nie mogę zmienić mojego projektu, jak poniżej rzucać wyjątki?

Ponadto nie potrzebuję żadnej synchronizacji (program ładujący klasy gwarantuje, że statyczna klasa wewnętrzna zostanie załadowana tylko raz i tylko wtedy, gdy wywołana zostanie funkcja getInstance()). W związku z tym wątki bezpieczne i lazily-utworzone?

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(); 
} 

Jeszcze raz dziękuję.

+1

Odpowiedź BalusC jest poprawna, ale zobacz także http://www.yoda.arachsys.com/csharp/singleton.html – finnw

+0

Dzięki. Chociaż wydaje się nieco niezwykłe, aby rzucić błąd. :) – CaptainHastings

+0

@finnw zaktualizowaną wersję linku: http://csharpindepth.com/Articles/General/Singleton.aspx –

Odpowiedz

34

Użyj statycznego inicjatora i przekaż Exception jak ExceptionInInitializerError. Kliknij łącze, aby przeczytać Javadoc, zobaczysz, że pasuje dokładnie do tego konkretnego wymagania funkcjonalnego: obsługa wyjątków podczas inicjalizacji statycznej . Singleton jest w rzeczywistości niczym mniej, niż statycznym i leniwie zainicjowanym obiektem globalnym.

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

Nie potrzeba double checked locking idiomu, który jest uważany za anty-wzorzec, aw niektórych przypadkach nawet niebezpieczne.

+3

(+1) Dzięki za uczenie mnie o EIIE – harschware

+0

@BalusC nie jest łatwiej stworzyć instancję wewnątrz prywatny konstruktor i obsługuje wyjątek? – oldergod

+0

@oldergod: Zastanawiam się, w jaki sposób zamierzasz utworzyć instancję w konstruktorze instancji bez uruchamiania się w nieskończoną pętlę, tworząc wiele instancji - naruszając wzór singleton. Poza tym OP wyraźnie wspomniał o stosowaniu metody Billa Pugha, więc kontynuowałem tę metodę. – BalusC

0

Po prostu nie wyrzucaj wyjątków od konstruktora obiektu. Możesz podać metodę init() i wyrzucić z niej swój wyjątek, jeśli będzie to konieczne.

0

Możesz sprawdzić NULL INSTANCE w getInstance i leniwie zainicjować. Ale zazwyczaj najlepiej, jeśli konstruktorzy nie rzucają, jeśli można uczynić konstruktora bezpieczniejszym, który byłby prawdopodobnie najlepszy.

-1

zgadzam się z Arne Burmeister, kod za to będzie wyglądać:

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. 
    } 

}