单例模式-C#

07-17 1147阅读

在C#中实现单例模式,主要目的是确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。以下是一个简单的单例模式实现示例,它使用了一个私有静态变量来保存类的唯一实例,并提供了一个公有的静态方法来获取这个实例。此外,还使用了私有构造函数来防止通过new关键字在类的外部创建实例。

单例模式-C#
(图片来源网络,侵删)

单例模式的优点:

    1. 单例模式可以保证一个类只有一个实例,减少内存开销,降低系统的复杂度,并加强系统的稳定性。
    1. 单例模式可以避免对资源的多重占用,保证系统的一致性。
    1. 单例模式可以全局访问点,可以提供一个访问点,使得外界可以直接访问该实例。
    1. 单例模式可以提供一个统一的访问点,简化调用,提高代码的可读性和可维护性。

    单例模式的缺点:

      1. 单例模式一般没有接口,扩展困难。
      1. 单例模式违反了依赖倒置原则,一个模块应该依赖于抽象,而不是具体的实现。
      1. 单例模式对测试不利,难以对单例进行单元测试。
      1. 单例模式在多线程环境下需要进行线程同步,可能会导致性能问题。
      1. 单例模式在一些框架中使用单例模式,可能会导致系统的复杂性。
      1. 单例模式在一些语言中不容易实现,比如Java中不能通过反射创建对象。
      1. 单例模式在一些场景下会增加系统的复杂度,比如多线程的应用场景。
      1. 单例模式在一些框架中使用单例模式,可能会导致系统的复杂性。
      1. 单例模式在一些语言中不容易实现,比如Java中不能通过反射创建对象。
      1. 单例模式在一些场景下会增加系统的复杂度,比如多线程的应用场景。

      懒汉式(线程不安全)

      这是最基本的实现方式,但在多线程环境下可能会创建多个实例。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      namespace SingletonPattern
      {
          /// 
          /// 懒汉式(线程不安全)
          /// 这是最基本的实现方式,但在多线程环境下可能会创建多个实例。
          /// 
          internal class Singleton_LazyNoSafety
          {
              // 私有静态变量,用于存储类的唯一实例
              private static Singleton_LazyNoSafety instance;
              // 私有构造函数,防止外部创建实例  
              private Singleton_LazyNoSafety() 
              {
                  Console.WriteLine("单例模式:懒汉式(线程不安全)!");
              }
              // 公有静态方法,返回类的唯一实例  
              public static Singleton_LazyNoSafety GetInstance()
              {
                  // 如果实例不存在,则创建实例
                  if (instance == null)
                  {
                      instance = new Singleton_LazyNoSafety();
                  }
                  return instance;
              }
          }
      }
      

      懒汉式(线程安全)

      通过在GetInstance方法上添加lock关键字来确保线程安全。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      namespace SingletonPattern
      {
          /// 
          /// 懒汉式(线程安全)
          /// 通过在GetInstance方法上添加lock关键字来确保线程安全。
          /// 
          public class Singleton_LazySafety
          {
              private static Singleton_LazySafety instance;
              /*
               * lock 关键字是用于同步代码块,确保在同一时间内只有一个线程可以执行该代码块。
               * lock 关键字通过锁定一个对象来工作,任何线程在尝试进入被 lock 保护的代码块之前,都必须先获得该对象的锁。
               * 如果一个线程已经获得了锁,其他线程就必须等待,直到锁被释放。当线程退出 lock 代码块时,无论是因为正常执行完毕还是由于异常退出,锁都会被自动释放。
               */
              private static readonly object lockObj = new object();
              private Singleton_LazySafety()
              {
                  Console.WriteLine("单例模式:懒汉式(线程安全)!");
              }
              public static Singleton_LazySafety GetInstance()
              {
                  lock (lockObj)
                  {
                      if (instance == null)
                      {
                          instance = new Singleton_LazySafety();
                      }
                  }
                  return instance;
              }
          }
      }
      

      饿汉式

      这种方式基于类加载机制避免了多线程同步问题,但是在类装载时就完成实例化,没有达到Lazy Loading的效果。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      namespace SingletonPattern
      {
          /// 
          /// 饿汉式
          /// 这种方式基于类加载机制避免了多线程同步问题,但是在类装载时就完成实例化,没有达到Lazy Loading的效果。
          /// 
          public class Singleton_Hungry
          {
              // 私有静态变量,用于存储类的唯一实例
              private static Singleton_Hungry instance;
              // 私有构造函数,防止外部创建实例  
              public Singleton_Hungry()
              {
                  Console.WriteLine("单例模式:饿汉式!");//在类被加载时就会创建实例对象,不会被打印到控制台
              }
              // 公有静态方法,返回类的唯一实例  
              public static Singleton_Hungry GetInstance() 
              { 
                  return instance; 
              }
          }
      }
      

      双重检查锁定(Double-Checked Locking)

      这种方式既保证了线程安全,又避免了每次调用GetInstance时都进行同步,从而提高了性能。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      namespace SingletonPattern
      {
          /// 
          /// 双重检查锁定(Double-Checked Locking)
          /// 这种方式既保证了线程安全,又避免了每次调用GetInstance时都进行同步,从而提高了性能。
          /// 
          public class Singleton_DoubleCheckedLocking
          {
              // 使用volatile关键字确保多线程环境下的可见性  
              private static volatile Singleton_DoubleCheckedLocking instance;
              private static readonly object lockObject = new object();
              private Singleton_DoubleCheckedLocking()
              {
                  Console.WriteLine("单例模式:双重检查锁定!");
              }
              public static Singleton_DoubleCheckedLocking GetInstance()
              {
                  // 第一次检查实例是否存在,如果不存在,才进入下面的同步块  
                  if (instance == null)
                  {
                      lock (lockObject)
                      {
                          // 第二次检查实例是否存在,防止多个线程都通过了第一次检查并创建实例  
                          if (instance==null)
                          {
                              instance = new Singleton_DoubleCheckedLocking();
                          }
                      }
                  }
                  return instance;
              }
          }
      }
      

      .NET Framework 4.0及更高版本

      请注意,在.NET Framework 4.0及更高版本中,由于System.Lazy的引入,实现单例模式变得更加简单和高效。Lazy类提供了一种延迟初始化的机制,它确保对象在其Value属性被访问之前不会被实例化。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      namespace SingletonPattern
      {
          /// 
          /// 4.0后高版本
          /// 在.NET Framework 4.0及更高版本中,由于System.Lazy的引入,实现单例模式变得更加简单和高效。
          /// Lazy类提供了一种延迟初始化的机制,它确保对象在其Value属性被访问之前不会被实例化。
          /// 
          internal class Singleton_HighVersion
          {
              // 使用Lazy实现单例模式  
              private static readonly Lazy lazy = new Lazy(() => new Singleton_HighVersion());
              // 私有构造函数  
              private Singleton_HighVersion()
              {
                  Console.WriteLine("单例模式:4.0后高版本!");
              }
              // 公有静态属性,返回类的唯一实例  
              public static Singleton_HighVersion Instance => lazy.Value;
          }
      }
      

      调用结果

      using System;
      namespace SingletonPattern
      {
          internal class Program
          {
              static void Main(string[] args)
              {
                  var instance_lazy1 = Singleton_LazyNoSafety.GetInstance();
                  var instance_lazy2 = Singleton_LazyNoSafety.GetInstance();
                  // 比较内存地址判断是否同一个实例  
                  Console.WriteLine(ReferenceEquals(instance_lazy1, instance_lazy2)); // 输出: True 
                  var instance_lazy3 = Singleton_LazySafety.GetInstance();
                  var instance_lazy4 = Singleton_LazySafety.GetInstance();
                  Console.WriteLine(ReferenceEquals(instance_lazy3, instance_lazy4)); 
                  //在类被加载时就会创建实例对象
                  var instance_hungry1 = Singleton_Hungry.GetInstance();
                  var instance_hungry2 = Singleton_Hungry.GetInstance();
                  Console.WriteLine(ReferenceEquals(instance_hungry1, instance_hungry2));
                  var instance_double1 = Singleton_DoubleCheckedLocking.GetInstance();
                  var instance_double2 = Singleton_DoubleCheckedLocking.GetInstance();
                  Console.WriteLine(ReferenceEquals(instance_double1, instance_double2));
                  var instance_high1 = Singleton_HighVersion.Instance;
                  var instance_hagh2 = Singleton_HighVersion.Instance;
                  Console.WriteLine(ReferenceEquals(instance_high1, instance_hagh2));
              }
          }
      }
      
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]