标签00标签001标签02标签03标签04标签05**
单例模式
定义
单例模式,属于创建类型的一种常用的设计模式。它的目的就是为了创建的类在当前进程中只有一个实例。
目的
- 全局唯一
-
优点
确保全局共享同一个实例
-
实现手段
1. 静态类
代码
public static class SingletonSample1
{
private static int _counter = 0;
public static int IncreaseCount()
{
return ++_counter;
}
}
:::tips 注意:这里的
++_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 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;
}
}
:::tips 注意:视频中讲到这里时,我其中有提到热启动关键词,我把系统预热口误说成了热启动,由于这两个概念之间有较大的差别,所以这里纠正一下。 :::
优点
-
缺点
-
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();
//此处双检锁也不一定完全解决了该问题,因为从底层出发,一般_instance = new SingletonSample5();包含三个步骤,即开辟空间,赋值,指向变量,但是CPU不见得按照一定顺序完成这样的操作,有可能是打乱的顺序;
//那么假如在赋值前,下一个进程进入双检锁,那么就会被重新赋值,所以这里需要添加volatile,那么就会让CPU严格按照开辟空间,赋值,指向变量的顺序执行。
}
}
}
return _instance;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
优点
-
缺点
-
6. 单例模式五
代码
public class SingletonSample6
{
//赖加载,需要的时候才会创建
private static readonly Lazy<SingletonSample6> _instance = new Lazy<SingletonSample6>(() => new SingletonSample6());
private int _counter = 0;
private SingletonSample6() { }
public static SingletonSample6 Instance
{
get
{
return _instance.Value;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
优点
-
缺点
-
7. 单例模式六
代码
```csharp 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
优点
-
缺点
-
另外
单例模式还可通过IOC容器实现,视频中在讲到IOC容器是也发生了多次口误,将注册说成了注入,这里也纠正一下。
- 最后举的一个用单例模式实现SqlHelper的例子,重点是为了突出相对于静态类,实例类在多态扩展方面的优势,其实如果没有类似这种扩展需求,静态类就足以应付绝大多数的需求,但视频的最后也忘了说。
- 本文作者:GeekPower - Felix Sun
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!