C#中利用泛型实现实例单件化 |
[ 2007-8-17 13:15:00 | By:
陈晴阳 ]
|
2
http://blog.csai.cn/user1/16236/archives/2007/17475.html
在多线程应用程序中,实现对象的单件(GoF Singleton模式)化是一项常用的设计方法。比如,对于需要维护同一资源的多线程服务器应用程序,对于表述该资源的对象实现单件模式,是一种常用的设计方法。在C#中,我们通常的做法是:
public class MyClass
{
private static volatile MyClass instance__; private static object syncRoot__ = new object();
private SingletonGeneric()
{ }
public static MyClass Instance
{ get { if (instance__ == null) { lock (syncRoot__) { if (instance__ == null) { instance__ = new MyClass(); } } } return instance__; } }
}
这种做法是C#中标准的实现单件模式的方法。设想,假如我们有多个类需要套用单件模式,那么,我们是否需要重复地编写上面的代码?
其实我们可以利用C# 2.0中的泛型类型来定义单件,并通过套用的方式来使得“实例单件化”:
public class SingletonGeneric<T> where T : new()
{ private static T instance__ = default(T); private static object syncRoot__ = new object();
private SingletonGeneric()
{ }
public static T Instance
{ get { if (instance__ == null) { lock (syncRoot__) { if (instance__ == null) { instance__ = new T(); } } } return instance__; } } }
那么我们在使用的时候,只需要“SingletonGeneric<MyClass>”就可以了。这样做的好处有三:
1、在定义单件类时,我们可以按照普通定义类的方式,而不需要考虑单件模式的具体实现,在真正需要用的地方直接套用SingletonGeneric<MyClass>即可;
2、当单件模式实现发生改变时,我们只需要修改SingletonGeneric<T>类,而不需要修改所有的单件类;
3、这种方法还可以使得系统中本不是单件类的类型单件化,比如,我的服务器应用程序采用一个Hashtable的对象来保存数据字典,那么,我只需要使用SingletonGeneric<Hashtable>的方法,就可以确保整个系统中只存在一个Hashtable对象副本。但是这样做的弊端也是显而易见:倘若应用程序需要维护两个Hashtable的单件实例,那么就会出现问题。解决方法是:定义两个继承于Hashtable的类,然后再用此方法。
这种方法也是《面向模式的软件体系结构(卷2:用于并发与网络化对象的模式)》一书中提到的一种模式惯用法。在C#中采用这种办法,有一个潜在的危险就是,我们无法在泛型T上使用volatile关键字。该关键字确保指定的类型对象在编译器处理时不被优化,以保证该对象所存储的值无论在任何时候都是最新的。我目前还没有办法证明,在C#中使用单件时,如果不采用volatile关键字是否真的会出现问题,如果有问题,又是否有其它替代方法解决。
|