当系统只需要一个实例对象,或者客户调用类的单个实例只允许一个公共访问点的时候,我们就需要单例类。
1.单例类的设计过程
1)为了确保外界无法创建对象,则需要将其构造函数私有化:
class TaskManager
{
private TaskManager()
{ }
}
2)内部需要返回对象的唯一实例,所以定义一个静态字段用来返回:
private static TaskManager tm = null;
3)建立一个公开的静态方法或属性,将唯一的实例返回,全部代码如下:
class TaskManager
{
private static TaskManager tm = null;
public static TaskManager GetTaskManager
{
get {
if (tm == null)
tm = new TaskManager();
return tm;
}
}
private TaskManager() { }
}
上面是一个简单的单例类。不过这个单例类在多线程的情况下仍然会有很大的可能创建多个对象。为了应付这种情况,我们可以采取3个方案。
1.饿汉单例类:
在类被加载时就创建实例对象,这样无论哪个线程获取的都是同一个实例:
private static TaskManager lb = new TaskManager();
public static TaskManager CurrentBalancer
{
get
{
return lb;
}
}
上面可在C#中简写为:
public static readonly TaskManager lb = new TaskManager();
2.懒汉单例类:
当类被调用时才创建实例(即延迟加载),主要通过使用线程锁:
private static object LockObject = new object();
public static TaskManager GetTaskManager
{
get
{
lock (LockObject)
{
if (tm == null)
tm = new TaskManager();
}
return tm;
}
}
3.IoDH(Initialization on Demand Holder):
饿汉单例类不用考虑线程问题,但系统资源利用低;懒汉模式系统资源利用率高,但线程安全太繁琐。而IoDH可以将其优点结合并摒弃缺点。
实现IoDH技术需要在单例类中添加一个静态的内部类,该内部类中创建单例类的对象。通过单例类中的方法返回这个实例:
class Singleton
{
private Singleton() {}
public static Singleton GetInstance()
{
return HolderClass.instance;
}
[Synchronization]//保证了此类型的任何公共静态成员都是线程安全的
private static class HolderClass
{
public static Singleton instance = new Singleton();
}
}
因为静态单例对象中需要实例化的成员移到了内部类中。所以在单例类被加载时不会实例化对象。但当第一次调用GetInstance()时,会加载内部类,这时才会返回一个被实例化的单例对象。