• 设计模式——单例模式


    确保一个类只有一个实例,并提供一个全局访问点

    • 当类只能有一个实例,而且客户可以从一个众所周知的访问点访问它时。
    • 当这个唯一的实例应该是通过子类化可扩展的,而且客户应该无需更改代码就能使用一个扩展的实例时。

    如何确保外部无法使用new来创建类的实例?在此类中将构造函数设为 private 

     1  /// <summary>
     2     /// 单例模式的实现
     3     /// </summary>
     4     public class Singleton
     5     {
     6         // 定义一个静态变量来保存类的实例
     7         private static Singleton uniqueInstance;
     8 
     9         // 定义私有构造函数,使外界不能创建该类实例
    10         private Singleton()
    11         {
    12         }
    13 
    14         /// <summary>
    15         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
    16         /// </summary>
    17         /// <returns></returns>
    18         public static Singleton GetInstance()
    19         {
    20             // 如果类的实例不存在则创建,否则直接返回
    21             if (uniqueInstance == null)
    22             {
    23                 uniqueInstance = new Singleton();
    24             }
    25             return uniqueInstance;
    26         }
    27     }

    在多线程的情况下会得到多个Singleton实例,因为在两个线程同时运行GetInstance方法时,此时两个线程判断(uniqueInstance ==null)这个条件时都返回真,此时两个线程就都会创建Singleton的实例,这样就违背了我们单例模式初衷了,既然上面的实现会运行多个线程执行,那我们对于多线程的解决方案自然就是使GetInstance方法在同一时间只运行一个线程运行就好了。

     1 /// <summary>
     2     /// 单例模式的实现
     3     /// </summary>
     4     public class Singleton
     5     {
     6         // 定义一个静态变量来保存类的实例
     7         private static Singleton uniqueInstance;
     8 
     9         // 定义一个标识确保线程同步
    10         private static readonly object locker = new object();
    11 
    12         // 定义私有构造函数,使外界不能创建该类实例
    13         private Singleton()
    14         {
    15         }
    16 
    17         /// <summary>
    18         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
    19         /// </summary>
    20         /// <returns></returns>
    21         public static Singleton GetInstance()
    22         {
    23             // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
    24             // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
    25             // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
    26             lock (locker)
    27             {
    28                 // 如果类的实例不存在则创建,否则直接返回
    29                 if (uniqueInstance == null)
    30                 {
    31                     uniqueInstance = new Singleton();
    32                 }
    33             }
    34 
    35             return uniqueInstance;
    36         }
    37     }

    上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(uniqueInstance==null)为假,此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式的缺陷,我们只需要在lock语句前面加一句(uniqueInstance==null)的判断就可以避免锁所增加的额外开销,这种实现方式我们就叫它 “双重锁定”

     1 /// <summary>
     2     /// 单例模式的实现
     3     /// </summary>
     4     public class Singleton
     5     {
     6         // 定义一个静态变量来保存类的实例
     7         private static Singleton uniqueInstance;
     8 
     9         // 定义一个标识确保线程同步
    10         private static readonly object locker = new object();
    11 
    12         // 定义私有构造函数,使外界不能创建该类实例
    13         private Singleton()
    14         {
    15         }
    16 
    17         /// <summary>
    18         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
    19         /// </summary>
    20         /// <returns></returns>
    21         public static Singleton GetInstance()
    22         {
    23             // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
    24             // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
    25             // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
    26             // 双重锁定只需要一句判断就可以了
    27             if (uniqueInstance == null)
    28             {
    29                 lock (locker)
    30                 {
    31                     // 如果类的实例不存在则创建,否则直接返回
    32                     if (uniqueInstance == null)
    33                     {
    34                         uniqueInstance = new Singleton();
    35                     }
    36                 }
    37             }
    38             return uniqueInstance;
    39         }
    40     }

    .NET FrameWork类库中有没有单例模式的实现呢?

    .NET类库中确实存在单例模式的实现类,不过该类不是公开的,下面就具体看看该类的一个实现的(该类具体存在于System.dll程序集,命名空间为System,大家可以用反射工具Reflector去查看源码的

     1 // 该类不是一个公开类
     2     // 但是该类的实现应用了单例模式
     3     internal sealed class SR
     4     {
     5         private static SR loader;
     6         internal SR()
     7         {
     8         }
     9         // 主要是因为该类不是公有,所以这个全部访问点也定义为私有的了
    10         // 但是思想还是用到了单例模式的思想的
    11         private static SR GetLoader()
    12         {
    13             if (loader == null)
    14             {
    15                 SR sr = new SR();
    16                 Interlocked.CompareExchange<SR>(ref loader, sr, null);
    17             }
    18             return loader;
    19         }
    20 
    21         // 这个公有方法中调用了GetLoader方法的
    22         public static object GetObject(string name)
    23         {
    24             SR loader = GetLoader();
    25             if (loader == null)
    26             {
    27                 return null;
    28             }
    29             return loader.resources.GetObject(name, Culture);
    30         }
    31     }

    学习于  https://www.cnblogs.com/zhili/p/SingletonPatterm.html

  • 相关阅读:
    js点击弹出div层
    图片按比例缩小
    js标题文字向上滚动
    JS刷新当前页面
    图片缩放显示,不变形
    产品叠加搜索
    Oracle中DML基础知识
    Oracle中DDL的基础知识
    Sql多对多关系中外键的应用
    oracle 中sql语句的几个基本函数..
  • 原文地址:https://www.cnblogs.com/cwmizlp/p/9141366.html
Copyright © 2020-2023  润新知