保证一个类仅有一个实例,并提供一个访问它的全局访问点。——DP
UML类图
模式说明
个人认为单例模式是所有设计模式中最为简单的一个模式,因为实现这个模式仅需一个类,而不像其他模式需要若干个类。这个模式中,需要注意的一点就是获取实例时的线程安全问题。
通常单例模式的实现方式如下:
class ToolBox{// 阻止外部实例化ToolBoxprivate ToolBox(){guid = Guid.NewGuid();}private static ToolBox instance;private static object lockObj = new object();//提供一个全局访问点public static ToolBox GetToolBoxInstance(){if (instance != null) return instance;//要考虑线程安全问题lock (lockObj){if (instance == null){instance = new ToolBox();}}return instance;}#region 用于测试private Guid guid;public void ShowGuid(){Console.WriteLine(guid.ToString());}#endregion}
另外,C#语言中提供一种“静态初始化”功能,对静态初始化器的调用是由CLR控制的,并且CLR会解决线程安全问题,保证只调用一次。所以也可以利用这个特性,来简化单例模式的C#实现:
class ToolBox2{// 阻止外部实例化ToolBox2private ToolBox2() { guid = Guid.NewGuid(); }//静态内联初始化private static readonly ToolBox2 instance = new ToolBox2();//提供一个全局访问点public static ToolBox2 GetToolBoxInstance(){return instance;}#region 用于测试private Guid guid;public void ShowGuid(){Console.WriteLine(guid.ToString());}#endregion}
客户端访问代码如下(从输出可以看到,每次访问获取的都是同一个实例):
static void Main(string[] args){// 测试单例模式for (int i = 0; i < 10; i++){new Thread(x =>ToolBox.GetToolBoxInstance().ShowGuid()).Start();}Thread.Sleep(200);Console.WriteLine();// 测试单例模式for (int i = 0; i < 10; i++){new Thread(x =>ToolBox2.GetToolBoxInstance().ShowGuid()).Start();}/* 输出如下f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd5f38db210-20bc-4c2d-8d43-40a0e58fedd58398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c8398be29-abd3-4abd-abf8-4fd09641427c*/Console.ReadKey();}
总结
单例模式和前面介绍的工厂模式(工厂方法、抽象工厂)都属于创建型模式,负责类的实例化过程。单例模式的实现过程,只需要一个类,算是最简单的一个模式,在多线程环境下,单例模式的实现必须保证线程安全,否则在多个线程同时访问时,可能产生多个实例。在C#中,可以通过语言本身的特性(静态初始化器)来更简洁地实现单例模式。
参考
- 程杰老师 《大话设计模式》