标签00标签001标签02标签03标签04标签05**

单例模式

定义

单例模式,属于创建类型的一种常用的设计模式。它的目的就是为了创建的类在当前进程中只有一个实例

目的

  • 全局唯一
  • 全局共享

    优点

  • 确保全局共享同一个实例

  • 节约系统资源

    实现手段

    1. 静态类

    不是单例模式,但可以满足需求,常用,可用于生产。

    代码

    1. public static class SingletonSample1
    2. {
    3. private static int _counter = 0;
    4. public static int IncreaseCount()
    5. {
    6. return ++_counter;
    7. }
    8. }

    :::tips 注意:这里的++_counter其实存在高并发问题,严格上应该用Interlocked.Increment(ref _counter)的方式,由于我们主要讲的是单例模式并且简单且能演示效果,所以故意忽略了这一点。下同 :::

    优点

  • 使用起来方便,简单

    缺点

  • 静态类不能继承类,实现接口,不能通过接口或者抽象方法(虚方法)实现多态;

  • 静态类必须在第一次加载时初始化,如果项目中用不到会导致资源浪费;

    2. 单例模式一

    最简单的一种单例模式,常用,可用于生产。

    代码

    1. public sealed class SingletonSample2
    2. {
    3. private static readonly SingletonSample2 _instance = new SingletonSample2();
    4. private int _counter = 0;
    5. private SingletonSample2() { }
    6. public static SingletonSample2 Instance
    7. {
    8. get
    9. {
    10. return _instance;
    11. }
    12. }
    13. public int IncreaseCount()
    14. {
    15. return ++_counter;
    16. }
    17. }

    优点

  • 解决了静态类不能继承类,实现接口,不能通过接口或者抽象方法(虚方法)实现多态的问题;

    缺点

  • 没有解决第一次加载时初始化,资源浪费的问题;

    3. 单例模式二

    过渡阶段,不可用于生产。

    代码

    1. public class SingletonSample3
    2. {
    3. private static SingletonSample3 _instance;
    4. private int _counter = 0;
    5. private SingletonSample3() { }
    6. public static SingletonSample3 Instance
    7. {
    8. get
    9. {
    10. if (_instance == null)
    11. {
    12. _instance = new SingletonSample3();
    13. }
    14. return _instance;
    15. }
    16. }
    17. public int IncreaseCount()
    18. {
    19. return ++_counter;
    20. }
    21. }

    优点

  • 解决了资源浪费的问题;

    缺点

  • 引入了高并发的新问题;

    4. 单例模式三

    过渡阶段,不可用于生产。

    代码

    1. public class public class SingletonSample4
    2. {
    3. private static SingletonSample4 _instance;
    4. private static readonly object _locker = new object();
    5. private int _counter = 0;
    6. private SingletonSample4() { }
    7. public static SingletonSample4 Instance
    8. {
    9. get
    10. {
    11. lock (_locker)
    12. {
    13. if (_instance == null)
    14. {
    15. _instance = new SingletonSample4();
    16. }
    17. return _instance;
    18. }
    19. }
    20. }
    21. public int IncreaseCount()
    22. {
    23. return ++_counter;
    24. }
    25. }

    :::tips 注意:视频中讲到这里时,我其中有提到热启动关键词,我把系统预热口误说成了热启动,由于这两个概念之间有较大的差别,所以这里纠正一下。 :::

    优点

  • 解决了高并发问题;

    缺点

  • 引入了性能问题;

    5. 单例模式四

    著名的双检锁模式,完美解决问题,可用于生产。

    代码

    1. public class SingletonSample5
    2. {
    3. private static volatile SingletonSample5 _instance;
    4. private static readonly object _locker = new object();
    5. private int _counter = 0;
    6. private SingletonSample5() { }
    7. public static SingletonSample5 Instance
    8. {
    9. get
    10. {
    11. if (_instance == null)
    12. {
    13. lock (_locker)
    14. {
    15. if (_instance == null)
    16. {
    17. _instance = new SingletonSample5();
    18. //此处双检锁也不一定完全解决了该问题,因为从底层出发,一般_instance = new SingletonSample5();包含三个步骤,即开辟空间,赋值,指向变量,但是CPU不见得按照一定顺序完成这样的操作,有可能是打乱的顺序;
    19. //那么假如在赋值前,下一个进程进入双检锁,那么就会被重新赋值,所以这里需要添加volatile,那么就会让CPU严格按照开辟空间,赋值,指向变量的顺序执行。
    20. }
    21. }
    22. }
    23. return _instance;
    24. }
    25. }
    26. public int IncreaseCount()
    27. {
    28. return ++_counter;
    29. }
    30. }

    优点

  • 解决了上述实现方式的各种设计缺陷;

    缺点

  • 代码有点复杂;

    6. 单例模式五

    .Net支持的一种优雅版本的实现方式,强烈建议使用该版本

    代码

    1. public class SingletonSample6
    2. {
    3. //赖加载,需要的时候才会创建
    4. private static readonly Lazy<SingletonSample6> _instance = new Lazy<SingletonSample6>(() => new SingletonSample6());
    5. private int _counter = 0;
    6. private SingletonSample6() { }
    7. public static SingletonSample6 Instance
    8. {
    9. get
    10. {
    11. return _instance.Value;
    12. }
    13. }
    14. public int IncreaseCount()
    15. {
    16. return ++_counter;
    17. }
    18. }

    优点

  • 代码优雅简洁同时满足需求

    缺点

  • 当系统中有大量单例模式时,会有较多重复代码

    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 {

    1. get
    2. {
    3. return _instance.Value;
    4. }

    } }

public class SingletonSample7 : SingletonSampleBase { private int _counter = 0; private SingletonSample7() { } public int IncreaseCount() { return ++_counter; } } ```

优点

  • 封装了重复代码

    缺点

  • 违反了依赖倒置原则

    另外

  • 单例模式还可通过IOC容器实现,视频中在讲到IOC容器是也发生了多次口误,将注册说成了注入,这里也纠正一下。

  • 最后举的一个用单例模式实现SqlHelper的例子,重点是为了突出相对于静态类,实例类在多态扩展方面的优势,其实如果没有类似这种扩展需求,静态类就足以应付绝大多数的需求,但视频的最后也忘了说。

  • 本文作者:GeekPower - Felix Sun
  • 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!