定义
单例模式,属于创建类型的一种常用的设计模式。它的目的就是为了创建的类在当前进程中只有一个实例。
目的全局唯一
全局共享
优点确保全局共享同一个实例
节约系统资源
实现手段
1. 静态类
不是单例模式,但可以满足需求,常用,可用于生产。
代码
public static class SingletonSample1
{
private static int _counter = 0;
public static int IncreaseCount()
{
return ++_counter;
}
}
注意:这里的++_counter其实存在高并发问题,严格上应该用Interlocked.Increment(ref _counter)的方式,由于我们主要讲的是单例模式并且简单且能演示效果,所以故意忽略了这一点。下同
优点使用起来方便,简单
缺点静态类不能继承类,实现接口,不能通过接口或者抽象方法(虚方法)实现多态;
静态类必须在第一次加载时初始化,如果项目中用不到会导致资源浪费;
2. 单例模式一
最简单的一种单例模式,常用,可用于生产。
代码
public sealed class SingletonSample2
{
private static readonly SingletonSample2 _instance = new SingletonSample2();
private int _counter = 0;
private SingletonSample2() { }
public static SingletonSample2 Instance
{
get
{
return _instance;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
优点解决了静态类不能继承类,实现接口,不能通过接口或者抽象方法(虚方法)实现多态的问题;
缺点没有解决第一次加载时初始化,资源浪费的问题;
3. 单例模式二
过渡阶段,不可用于生产。
代码
public class SingletonSample3
{
private static SingletonSample3 _instance;
private int _counter = 0;
private SingletonSample3() { }
public static SingletonSample3 Instance
{
get
{
if (_instance == null)
{
_instance = new SingletonSample3();
}
return _instance;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
优点解决了资源浪费的问题;
缺点引入了高并发的新问题;
4. 单例模式三
过渡阶段,不可用于生产。
代码
public class SingletonSample4
{
private static SingletonSample4 _instance;
private static readonly object _locker = new object();
private int _counter = 0;
private SingletonSample4() { }
public static SingletonSample4 Instance
{
get
{
lock (_locker)
{
if (_instance == null)
{
_instance = new SingletonSample4();
}
return _instance;
}
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
注意:视频中讲到这里时,我其中有提到热启动关键词,我把系统预热口误说成了热启动,由于这两个概念之间有较大的差别,所以这里纠正一下。
优点解决了高并发问题;
缺点引入了性能问题;
5. 单例模式四
著名的双检锁模式,完美解决问题,可用于生产。
代码
public class SingletonSample5
{
private static volatile SingletonSample5 _instance;
private static readonly object _locker = new object();
private int _counter = 0;
private SingletonSample5() { }
public static SingletonSample5 Instance
{
get
{
if (_instance == null)
{
lock (_locker)
{
if (_instance == null)
{
_instance = new SingletonSample5();
}
}
}
return _instance;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
优点解决了上述实现方式的各种设计缺陷;
缺点代码有点复杂;
6. 单例模式五
.Net支持的一种优雅版本的实现方式,强烈建议使用该版本。
代码
public class SingletonSample6
{
private static readonly Lazy _instance
= new Lazy(() => new SingletonSample6());
private int _counter = 0;
private SingletonSample6() { }
public static SingletonSample6 Instance
{
get
{
return _instance.Value;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
优点代码优雅简洁同时满足需求
缺点当系统中有大量单例模式时,会有较多重复代码
7. 单例模式六
泛型版本,是否使用视情况而定。
代码
public class SingletonSampleBase where TSingleton : class
{
private static readonly Lazy _instance
= new Lazy(() => (TSingleton)Activator.CreateInstance(typeof(TSingleton), true));
protected SingletonSampleBase() { }
public static TSingleton Instance
{
get
{
return _instance.Value;
}
}
}
public class SingletonSample7 : SingletonSampleBase
{
private int _counter = 0;
private SingletonSample7() { }
public int IncreaseCount()
{
return ++_counter;
}
}
优点封装了重复代码
缺点违反了依赖倒置原则
另外单例模式还可通过IOC容器实现,视频中在讲到IOC容器是也发生了多次口误,将注册说成了注入,这里也纠正一下。
最后举的一个用单例模式实现SqlHelper的例子,重点是为了突出相对于静态类,实例类在多态扩展方面的优势,其实如果没有类似这种扩展需求,静态类就足以应付绝大多数的需求,但视频的最后也忘了说。
视频路径