定义
保证一个类仅有一个实例,并提供一个该实例的全局访问点。 --《设计模式GoF》
UML类图
使用场景
- 当类只能有一个实例并且用户可以从一个众所周知的访问点访问它时。
- 创建一个对象需要消耗过多的资源,比如IO和数据库连接等。
C#代码实现
1,初始版本
namespace DesignPatternDemo.ConsoleApp { /// <summary> /// 单例类 /// </summary> public class Singleton { private static Singleton _singleton; private Singleton() { } public static Singleton GetInstance() { if (_singleton== null) { _singleton = new Singleton(); } return _singleton; } } }
注意:此版本在多线程环境下不能保证线程安全!
2,双检锁
namespace DesignPatternDemo.ConsoleApp { /// <summary> /// 单例类(双检锁) /// </summary> public class SingletonV2 { private static SingletonV2 _singleton; private static readonly object lockObj = new object(); private SingletonV2() { } public static SingletonV2 GetInstance() { if (_singleton == null) { lock (lockObj) { if (_singleton == null) { _singleton = new SingletonV2(); } } } return _singleton; } } }
总结:双检锁版本解决了多线程环境下线程安全的问题。
3,饿汉式版本
namespace DesignPatternDemo.ConsoleApp { /// <summary> /// 单例类(饿汉式版本) /// </summary> public class SingletonV3 { private static readonly SingletonV3 _singleton = new SingletonV3(); private SingletonV3() { } public static SingletonV3 GetInstance() { return _singleton; } } }
总结:这个版本的优点是实现简单并且没有加锁执行效率高,缺点是类加载时就初始化,可能会浪费内存资源。
4,测试
namespace DesignPatternDemo.ConsoleApp { class Program { static void Main(string[] args) { SingletonV2 singleton1 = SingletonV2.GetInstance(); SingletonV2 singleton2 = SingletonV2.GetInstance(); if (singleton1 == singleton2) { Console.WriteLine("对象singleton1和对象singleton2是同一个对象!"); } Console.ReadKey(); } } }
运行结果: