设计模式-单例模式

1、单例模式介绍

  单例顾名思义也就是说一个类只能有一个实例

2、单例模式组成

  单件实例(Singleton):这个模式里面只有一个类型,就是Singleton类型,并且这个类只有一个实例,可以通过Instance()方法获取该类型的实例

3、单例模式代码实现

3.1、单线程

/// <summary>
/// 单例模式的实现(单线程)
/// </summary>
public sealed class Singleton
{
    // 定义一个静态变量来保存类的实例
    private static Singleton uniqueInstance;
    // 定义私有构造函数,使外界不能创建该类实例
    private Singleton()
    {
    }
    /// <summary>
    /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
    /// </summary>
    /// <returns></returns>
    public static Singleton GetInstance()
    {
        // 如果类的实例不存在则创建,否则直接返回
        if (uniqueInstance == null)
        {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

私有的实例构造器是屏蔽外界的调用,上面的单例模式的实现在单线程下确实是完美的,也很好的满足了我们单线程环境的需求。
单线程单例模式的几个要点:
(1)、Singleton模式中的实例构造器可以设置为protected以允许子类派生。
(2)、Singleton模式一般不要支持ICloneable接口,因为这可能会导致多个对象实例,与Singleton模式的初衷违背。
(3)、Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。
(4)、Singletom模式只考虑到了对象创建的工作,没有考虑对象销毁的工作。为什么这样做呢,因为Net平台是支持垃圾回收的,所以我们一般没有必要对其进行销毁处理。
(5)、不能应对多线程环境:在多线程环境下,使用Singleton模式仍然有可能得到Singleton类的多个实例对象

3.2、多线程

    /// <summary>
  /// 单例模式的实现
  /// </summary>
  public sealed class Singleton
  {
      // 定义一个静态变量来保存类的实例
      private static Singleton uniqueInstance;
      // 定义一个标识确保线程同步
      private static readonly object locker = new object();
      // 定义私有构造函数,使外界不能创建该类实例
      private Singleton()
      {
      }
      /// <summary>
      /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
      /// </summary>
      /// <returns></returns>
      public static Singleton GetInstance()
      {
          // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
          // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
          // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
          lock (locker)
          {
              // 如果类的实例不存在则创建,否则直接返回
              if (uniqueInstance == null)
              {
                  uniqueInstance = new Singleton();
              }
          }
          return uniqueInstance;
      }
  }

3.3、双重锁定

/// <summary>
/// 单例模式的实现
/// </summary>
public sealed class Singleton
{
    // 定义一个静态变量来保存类的实例
    private static Singleton uniqueInstance;
    // 定义一个标识确保线程同步
    private static readonly object locker = new object();
    // 定义私有构造函数,使外界不能创建该类实例
    private Singleton()
    {
    }
    /// <summary>
    /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
    /// </summary>
    /// <returns></returns>
    public static Singleton GetInstance()
    {
        // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
        // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
        // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
        // 双重锁定只需要一句判断就可以了
        if (uniqueInstance == null)
        {
            lock (locker)
            {
                // 如果类的实例不存在则创建,否则直接返回
                if (uniqueInstance == null)
                {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

4、单例模式实现要点

1、Singleton模式是限制而不是改进类的创建。

2、Singleton类中的实例构造器可以设置为Protected以允许子类派生。

3、Singleton模式一般不要支持Icloneable接口,因为这可能导致多个对象实例,与Singleton模式的初衷违背。

4、Singleton模式一般不要支持序列化,这也有可能导致多个对象实例,这也与Singleton模式的初衷违背。

5、Singleton只考虑了对象创建的管理,没有考虑到销毁的管理,就支持垃圾回收的平台和对象的开销来讲,我们一般没必要对其销毁进行特殊的管理。

6、理解和扩展Singleton模式的核心是“如何控制用户使用new对一个类的构造器的任意调用”。

7、可以很简单的修改一个Singleton,使它有少数几个实例,这样做是允许的而且是有意义的。

5、单例模式优缺点

1、单例模式的优点:

(1)、实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例

(2)、灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程

2、单例模式的缺点:

(1)、开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

(2)、可能的开发混淆:使用 singleton 对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用 new 关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

(3)、对象的生存期:Singleton 不能解决删除单个对象的问题。因为它包含对该静态的私有字段的引用,静态字段是不能被CLR回收内存的,该实例会和应用程序生命周期一样长,一直存在。

3、单例模式的使用场合:

(1)、当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

(2)、当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

6、总结

到这里,单例模式就介绍完了,这个模式很简单,理解起来也不是很难,只要把握住代码的实现技巧,一般问题都不大,但是要找好使用的时机,如果使用错误,一些逻辑错误比较难排查。
posted @ 2022-12-28 09:50  木头马尾、、、  阅读(57)  评论(0)    收藏  举报