2010-02-17 73 views
28

什麼是設計一個可能拋出異常的單例類的最佳方式?單身人士和例外

在這裏,我有一個單身人士(使用Bill Pugh的方法,記錄在Wiki for 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; 
    } 

如果在2引發異常,我想將它傳播給調用者。 但是,我不能從第1行拋出異常。

所以,如果單身人士對象沒有被正確創建,是我唯一的選擇返回空對象嗎?

感謝

P.S我不知道這辛格爾頓可以打破如果通過不同類加載器加載,或者加載本能,但它不夠好我的目的。

// UPDATE

我很好奇,我不能重新安排如下我的設計拋出異常?另外,我不需要任何同步(類加載器保證靜態內部類只會在調用getInstance()時才加載一次)。因此,線程安全和懶惰實例化?

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

再次感謝。

+1

BalusC的答案是正確的,但也請參閱http://www.yoda.arachsys.com/csharp/singleton.html – finnw 2010-02-18 00:31:05

+0

謝謝。儘管拋出錯誤確實感覺有點不尋常。 :) – CaptainHastings 2010-02-18 16:41:20

+0

@finnw更新版本的鏈接:http://csharpindepth.com/Articles/General/Singleton.aspx – 2012-04-25 21:13:35

回答

34

使用靜態初始化和重新拋出ExceptionExceptionInInitializerError。點擊鏈接閱讀Javadoc,你會發現它完全適合這個特殊的功能要求:在靜態初始化期間處理異常。實際上,單身實際上不過是一個靜態和懶惰地初始化的全局對象。

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

無需這被認爲是一個反模式double checked locking成語並在某些情況下甚至是不安全的。

+3

(+1)感謝教我關於EIIE – harschware 2010-02-18 05:32:30

+0

@BalusC是不是更容易創建內部實例一個私有構造函數並在那裏處理異常? – oldergod 2013-11-05 08:40:08

+0

@oldergod:我想知道你打算如何在實例的構造函數中創建一個實例,而不會陷入創建多個實例的無限循環 - 違反了單例模式。此外,OP明確提到使用Bill Pugh的方法,所以我繼續採用這種方法。 – BalusC 2013-11-05 08:43:50

0

只是不要從對象的構造函數中拋出異常。如果有必要,您可以提供init()方法並從那裏拋出異常。

0

您可以檢查getInstance中的null INSTANCE,並且懶惰地初始化它。但如果構造函數不拋出,通常最好,如果你可以使構造函數更安全,可能是最好的。

-1

我阿恩螻蛄同意,該代碼將看起來像:

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

}