在决定使用单例与静态类之间进行设计考虑.在这样做时,你有点被迫对比这两者,所以无论你能想出什么对比,都有助于展示你的思考过程!此外,每位采访者都喜欢看到说明性的例子.:)
单身人士可以实现接口并从其他类继承.
单身人士可以懒惰加载.只有在实际需要的时候.如果初始化包括昂贵的资源加载或数据库连接,这非常方便.
单身人士提供了一个实际的对象.
单身人士可以扩展到工厂.幕后的对象管理是抽象的,因此它可以更好地维护并产生更好的代码.
如何"避免两者"?单身人士和静态课程:
可能会介绍全球状态
紧密耦合到其他多个类
隐藏依赖项
可以使单元测试类孤立起来很困难
相反,请查看依赖注入和控制容器库的反转.一些IoC库将为您处理生命周期管理.
(与往常一样,有一些例外,例如静态数学类和C#扩展方法.)
我认为唯一的区别是语法:MySingleton.Current.Whatever()vs MySingleton.Whatever().正如大卫所说,国家在任何一种情况下最终都是"静态的".
编辑:埋葬旅从digg过来......无论如何,我想到了一个需要单身的情况.静态类不能从基类继承,也不能实现接口(至少在.Net中它们不能).因此,如果您需要此功能,则必须使用单例.
关于这个问题,我最喜欢的讨论之一就在这里(原始站点下来,现在链接到Internet Archive Wayback Machine.)
总结Singleton的灵活性优势:
Singleton可以很容易地转换成工厂
可以轻松修改Singleton以返回不同的子类
这可以导致更易于维护的应用程序
带有静态变量的静态类有点像黑客.
/** * Grotty static semaphore **/ public static class Ugly { private static int count; public synchronized static void increment(){ count++; } public synchronized static void decrement(){ count--; if( count<0 ) { count=0; } } public synchronized static boolean isClear(){ return count==0; } }
具有实际实例的单例更好.
/** * Grotty static semaphore **/ public static class LessUgly { private static LessUgly instance; private int count; private LessUgly(){ } public static synchronized getInstance(){ if( instance==null){ instance = new LessUgly(); } return instance; } public synchronized void increment(){ count++; } public synchronized void decrement(){ count--; if( count<0 ) { count=0; } } public synchronized boolean isClear(){ return count==0; } }
该州仅在该实例中.
因此,稍后可以修改单例以执行池化,线程局部实例等.并且所有已编写的代码都不需要更改以获得好处.
public static class LessUgly { private static Hashtablesession; private static FIFO freePool = new FIFO (); private static final POOL_SIZE=5; private int count; private LessUgly(){ } public static synchronized getInstance(){ if( session==null){ session = new Hashtable (POOL_SIZE); for( int i=0; i < POOL_SIZE; i++){ LessUgly instance = new LessUgly(); freePool.add( instance) } } LessUgly instance = session.get( Session.getSessionID()); if( instance == null){ instance = freePool.read(); } if( instance==null){ // TODO search sessions for expired ones. Return spares to the freePool. //FIXME took too long to write example in blog editor. } return instance; }
可以使用静态类执行类似的操作,但间接调度中将存在每个调用的开销.
您可以获取实例并将其作为参数传递给函数.这使代码可以指向"正确"的单例.我们知道你只需要其中一个...直到你不需要它.
最大的好处是有状态的单身人士可以成为线程安全的,而静态的单人则不能,除非你把它修改成一个秘密的单身人士.