设计模式-Singleton

需求:需要一个类,这个类只能有一个实例。

首先看一个很简单的例子

Code

 

这个例子是在简单不过的了.这里用了一个属性,其实改用方法也一样,如下

   

Code

注意,这里用了一个技巧,或者也可以称做一种模式.那就是Lazy-Allocate(缓分配),或者Lazy-Load.
if(instance == null)
{
    instance = new Singleton();
}
.NET Framework中大量的使用了这种方法,Lazy-Allocate的设计概念很简单,就是未使用前不预付成本。


但是这种方式在单线程下确实运行的很好.一旦到了多线程就可能出现多个实例


需求:多线程环境下的单例

 

 

Code


首先多线程下判断instance为null的时候才可以进行实例,而实例化的时候要加一个锁
这里lockHelper,可以是你自己的有用的代码,也可以是一个仅仅起标识作用的不参与运算的对象
然后在判断是否实例化.这个方法也叫Double Check.

大家注意到private static volatile Singleton instance;多了一个关键字 volatile,这个是什么用的呢
就是在编译的时候,不要让Runtime调整编译指令的顺序

因为DotNet在编译的时候会对指令进行优化调整.所以即便用了Double Check还是有很小的机会创建多个Singleton的实例

所以我们加上volatile关键字,让Runtime不对这个instance做指令调整.这样就完全实现了多线程的Singleton.

有没有更简洁一点的用法呢.

看下面的例子

 

Code

这样就可以实现在多线程环境下的Singleton模式.为什么?

回忆一下readonly的用法,他本身就是只能进行一次初始化,然后就和const没什么区别.

那么还有一个问题.如果我的构造函数是有参数的时候该怎么办呢.

 

 

Code

这样本来需要在构造函数中需要的参数,我们把它改成一个属性.让这个属性是可以修改的..

噢,还可以考虑的解决方案.但是问题还是有.

比如有时候一些参数是有依赖性的.最好放在构造函数执行该怎么办呢.

看下面的代码

 

 

Code


首先在私有构造函数中,我们把要执行的code转移到Init方法中,让私有构造函数是空.
这样我们保证了它是一个Singleton

其次必须使用Init来初始化这个对象.如果没有初始化就引用,这个时候抛出异常.

第三.Init方法也只执行一次.

这样一个保证多线程环境下,任意参数的构造的一个Singleton模式就完成了.

当然设计模式就是一种思想,不能生搬硬套.具体环境具体操作.


在单例模式的使用中,要注意一下几个方面:

Singleton模式中的构造器也可以设置为protected允许子类派生
Singleton模式一般不要支持ICloneable接口,避免导致多个对象实例
Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例
小心应对多线程环境;

Singleton的关键是只能生成一个实例,在推敲一下,就是只能生成固定数量的实例,那么这种情况下,Singleton就是一个特例.

关于生成固定数量的实例,有兴趣的朋友可以自行研究一下.

posted @ 2009-04-16 18:21  PlutoWang  阅读(228)  评论(0编辑  收藏  举报