现在的位置: 首页 > 综合 > 正文

Singleton Pattern 两种实现的选择

2013年01月06日 ⁄ 综合 ⁄ 共 1403字 ⁄ 字号 评论关闭

    单件模式就不用多介绍了,其实现有两种主流的思路:Double Check和Static,两种方案的C#终极代码大致如下。


方案一:加锁

 

方案二:静态构造


方案一的代码还不够终结,有一些特殊的关键字没有加,不过结构就是这样了。这是最传统的思路,加锁来防止并发,演化为使用双判断来最大化的避免并发。优点是稳重可靠,缺点是使用锁损耗性能。

方案二的思路是利用静态构造的特性,来保证成员只会被加载一次。很巧妙,但是有个缺点是所需的单件实例加载的会太早,于是有了这个终极方案,使用嵌套类来延迟加载。更加巧妙,优点很显然,性能没有缺陷,缺点么,只能在静态构造器中实例化。


    我以前是很喜欢方案二的,讨厌加锁,而且利用静态构造器自己琢磨出来过,很有感情。所以仅从代码实现面上考虑,方案二绝对好于一。

但是方案二有个致命的缺陷,至少我一直没有办法弥补:

如果初始化时失败了,如何恢复?


    假设我们用方案二提供一个单件的消息服务连接,当第一次访问的时候,网络恰巧断线了,创建连接失败,对象为null。当第二次访问的时候,当然还是null,如何恢复呢?因为这时候无法再利用静态构造器了,难道你要抛个异常告诉Admin,请重启程序来重新连接么。只好每次访问的时候都判断并实例化,显然这需要加锁的,又回到了第一种方案上了。或者使用标志来记录状态、或使用循环来自我恢复,还是都需要加锁的,只是位置不同而已。何况,即便是初始化成功,第N次连接失败,第N+1次也是应该尝试恢复的。

    那么还有一种场景也不好用方案二,就是提供的这个单件需要释放对象、更改状态。方案二是无法提供这些功能的。道理很显然,更改了之后你无法恢复。

  

   所以,两者的比较要补充:Double Check的适用面是完美的,性能有损;Static的性能是完美的,适用不强。

   凡是需要对外提供更改状态、或者会有异常引起内部状态变更的服务,都不适用方案二来实现。换句话说,绝对只读的、异常可控的单件服务,才适合使用方案二实现。其他的情况,您还是老老实实的用锁吧。毕竟需求第一,性能靠后。

 

   当然,按照大师们所说,若是您能够把单件模式都重构掉可以不用,那是最好不过了。


-------------

今天居然不加班了,影响了计划。

写点小东西找找感觉,结果CSDN很卡,没感觉。而且用IE打开比用FF还慢了一倍。

抱歉!评论已关闭.