场景:微软的windows xp操作系统,ctrl+alt+del键都会弹出一个windows任务管理器(这时不关闭这个任务管理器),继续ctrl+alt+del键还是一个windows任务管理器。鉴于本人水平有限,上面的场景举例可能不合适,但是很接近一个基本的设计模式:单例模式。Code is cheap.下面用c#代码模拟出一个类似任务管理器的创建:
Code
using System;
/// <summary>
/// Singleton 单例模式
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
if (wtm==null)
{
wtm = new WindowsTaskManager();
}
return wtm;
}
}
/// <summary>
/// 客户端调用
/// </summary>
public class Client {
static void Main(string[] args)
{
WindowsTaskManager myWtm = WindowsTaskManager.CreateSingleWtm();
WindowsTaskManager myWtm1 = WindowsTaskManager.CreateSingleWtm();
if (myWtm==myWtm1)
{
Console.WriteLine("两个对象是相同的实例.");
}
}
}
上面创建实例的基本思想是new一个对象的时候,判断静态的类变量是否已经有实例,构造函数私有,这样外部代码不能直接new来实例化对象。这是因为我们都知道所有类都有构造函数,不编码写构造函数则系统默认生成无参数的构造方法,但如果有显式定义的构造方法,默认的就会失效。ps:在定义可序列化的类的时候,默认构造函数是必须的,所以如果你显式定义了一个带参数的构造方法,一定不能忘记要再写一个没有参数的构造方法。
using System;
/// <summary>
/// Singleton 单例模式
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
if (wtm==null)
{
wtm = new WindowsTaskManager();
}
return wtm;
}
}
/// <summary>
/// 客户端调用
/// </summary>
public class Client {
static void Main(string[] args)
{
WindowsTaskManager myWtm = WindowsTaskManager.CreateSingleWtm();
WindowsTaskManager myWtm1 = WindowsTaskManager.CreateSingleWtm();
if (myWtm==myWtm1)
{
Console.WriteLine("两个对象是相同的实例.");
}
}
}
好了,上面的代码ms已经简单的实现了对唯一实例的受控访问。不过在多线程的程序中,上面的代码会有可能创建多个实例的。给进程加把锁,用lock解决一下:
Code
using System;
using System.Threading;
/// <summary>
/// Singleton
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private static readonly object syncRoot = new object();// 程序运行时创建一个静态只读的进程辅助对象
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
lock (syncRoot)
{
if (wtm == null)
{
wtm = new WindowsTaskManager();
}
}
return wtm;
}
}
上面那种做法可以创建单一实例,可是每次调用创建方法时,都要lock,影响性能,有一种双重锁定的方法:
using System;
using System.Threading;
/// <summary>
/// Singleton
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private static readonly object syncRoot = new object();// 程序运行时创建一个静态只读的进程辅助对象
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
lock (syncRoot)
{
if (wtm == null)
{
wtm = new WindowsTaskManager();
}
}
return wtm;
}
}
Code
using System;
using System.Threading;
/// <summary>
/// Singleton 双重锁定
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private static readonly object syncRoot = new object();// 程序运行时创建一个静态只读的进程辅助对象
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
if (wtm == null) //当wtm为空时,如果这时有两个线程同时调用CreateSingleWtm方法
{
lock (syncRoot)
{
if (wtm == null) // 很关键,没有这个判断,进入的两个线程就可以创建两个实例了
{
wtm = new WindowsTaskManager();
}
}
}
return wtm;
}
}
最后再看一个所谓的饿汉式单例类:
using System;
using System.Threading;
/// <summary>
/// Singleton 双重锁定
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private static readonly object syncRoot = new object();// 程序运行时创建一个静态只读的进程辅助对象
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
if (wtm == null) //当wtm为空时,如果这时有两个线程同时调用CreateSingleWtm方法
{
lock (syncRoot)
{
if (wtm == null) // 很关键,没有这个判断,进入的两个线程就可以创建两个实例了
{
wtm = new WindowsTaskManager();
}
}
}
return wtm;
}
}
Code
using System;
using System.Threading;
/// <summary>
/// Singleton sealed防止派生增加实例
/// </summary>
public sealed class WindowsTaskManager
{
private static readonly WindowsTaskManager wtm=new WindowsTaskManager();
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
return wtm;
}
}
using System;
using System.Threading;
/// <summary>
/// Singleton sealed防止派生增加实例
/// </summary>
public sealed class WindowsTaskManager
{
private static readonly WindowsTaskManager wtm=new WindowsTaskManager();
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
return wtm;
}
}