少年听雨歌楼上,红烛昏罗帐.壮年听雨客舟中,江阔云低断雁叫西风. 而今听雨僧庐下,鬓已星星也! 悲欢离合总无情,一任阶前点滴到天明。

2007年4月1日星期日

高级“单件”(Advanced Singleton Pattern)

高级“单件”(Advanced Singleton Pattern)
单件模式应该是设计模式中应用非常广泛的一种模式。单件模式可以确保某些类仅拥有一个实例化的对象。在实际的应用程序中,诸如打印机,内核,窗体控制类都常常应用为单件模式。然而,我们又常常遇到这样的问题,一个应用程序中有很多类都是单件类,该如何管理这些单件类呢?
单件的实现方法不尽相同,在一个应用程序中,我们可能很难知道哪些类是单件模式,哪些类不是。如果能够给所有的单件类提供一个统一的入口,能够十分快捷地得到一个单件类的实例,对于一个大型的应用程序来说,无疑是十分必要的。
这里我们实现了一个单件管理类,用于管理整个程序的所有单件。部分内容参考了《设计模式》一书。
我们的设计目标有两个:
1.每个单件类都不能够显示地实例化。
2.每个单件类都仅能够通过单件管理类来访问,换句话说,直接访问单件类的实例也是不行的。
这样做的目的就是想整个程序仅有一个单件的入口。下面展示的就是事例代码,由C# 2.0写成,用到了.NET的泛型。
public interface ISingleton
{

}
public class SingletonManager where T : ISingleton
{
Dictionary _singletons;
public static readonly SingletonManager Instance = new SingletonManager();
private SingletonManager ( )
{
_singletons = new Dictionary();
}
public bool CheckInstance ( string name )
{
return _singletons.ContainsKey(name);
}
public void Add ( string name, ISingleton single )
{
if (_singletons.ContainsKey(name) == false)
_singletons.Add(name, single);
}
public T GetInstance ( string name )
{
if (_singletons.ContainsKey(name) == true)
return (T)_singletons[name];
return default(T);
}
}
这就是单件管理类的代码和单件的接口。值得注意的是,单件的接口是一个空的接口。下面我们看看一个单件类是如何实现的:
public class ABC:ISingleton
{
private static ABC _instance;

pviate ABC() { }
public static void Register()
{
if (_instance == null)
_instance = new ABC();
SingletonManager.Instance.Add("abc", _instance);
}
public void Print()
{
Console.WriteLine("Hello");
}
}
我们注意到ABC类实现了ISingleton接口。其实,ISingleton接口仅仅是想让单件类有一个统一的原型。同样可以使用一个abstract 类。我们注意到,ABC不能直接实例化,也不能通过直接访问ABC来得到ABC的实例。唯一可以直接访问ABC的是一个静态方法,即向单件管理类中注册当前ABC的实例。而ABC的实例化就是在注册的时候完成的。
要想得到ABC的实例必须通过访问单件管理类:
ABC a = SingletonManager.Instance.GetInstance("abc");
注意,我们这里使用泛型完全是为了客户端代码的类型安全而考虑的。SingletonManager中存放的是ISingleton的集合,但实际上我们想得到ABC的实例。于是通过泛型通知SingletonManager我们想得到的类型,从而免去了类型的强制转换。
这样我们可以很容易知道一个类究竟是不是单件类,也很容易去控制单件类的行为。

2 条评论:

Sleipnir 说...

C# 本身有垃圾回收的机制,在你的代码里就不用考虑析构的问题。C++ 版本的就必须考虑这个问题。
我个人认为,实现单件继承是完全可能的,但并不一定是必要的。继承似乎并不会减少实际单件类的很多代码。当然,用一个单件池来管理所有单件可以保证让单件们合理有效地运行,但这个单件池也是单间的话,析构问题仍然存在。

洪亮劼 说...

是这样的,我的目的并不是要解决析构,因为这个问题在.NET和很多有垃圾回收的环境下根本不存在。我想解决的是,大量单件的管理问题。