2010-02-17 98 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. 
    } 

}