(超详细,超易懂)设计模式(六):单例模式,猴子八戒争蟠桃,唐僧建议共分享

如果你也喜欢C#开发或者.NET开发,可以关注我,我会一直更新相关内容,并且会是超级详细的教程,只要你有耐心,基本上不会有什么问题,如果有不懂的,也可以私信我加我联系方式,我将毫无保留的将我的经验和技术分享给你,不为其他,只为有更多的人进度代码的世界,而进入代码的世界,最快捷和最容易的就是C#.NET,准备好了,就随我加入代码的世界吧!
一、模式简介

        单例模式是一种设计模式,它限制一个类只能创建一个实例,确保在全局范围内都能通过该实例访问该类的唯一对象。

        在单例模式中,类的构造方法是私有的,这意味着不能通过 new 关键字来创建类的实例。而是通过一个静态方法获取该类的唯一实例。

单例模式有以下特点:

  1. 保证一个类只有一个实例;
  2. 提供一个全局访问点,方便其他类获取该实例;
  3. 对该实例进行控制,确保只有一个实例存在。

        单例模式的实现可以有多种方式,常见的有饿汉式、懒汉式、双重校验锁等。不同的实现方式有不同的优缺点,需要根据具体情况选择合适的方式。                

二、为什么要学习单例模式

        2.1 简化对象的创建和管理

        单例模式保证了一个类只有一个实例存在,可以节省内存和系统资源的开销,使得对象的创建和管理更加简单。

        2.2 全局访问点

        通过单例模式创建的对象可以在整个应用程序中被访问,方便其他类使用。

        2.3 数据共享和协调

        单例模式可以确保多个对象共享相同的状态和数据,方便不同模块之间的协作。

        2.4避免资源冲突

        在多线程环境下,使用单例模式可以避免多个线程同时访问和修改同一资源的问题,提高程序的稳定性和可靠性。

        2.5 控制实例化过程

        通过单例模式可以对对象的实例化过程进行控制,保证符合业务需求和设计规范。

三、单例模式在项目中有哪些实际应用

        3.1 线程池

        线程池在项目中被广泛使用,一般使用单例模式来保证线程池的全局唯一性,以便在整个项目中共享线程池。

        3.2 数据库连接池

        在项目中使用数据库连接池来管理数据库连接,提高数据库的性能和资源利用率。数据库连接池往往采用单例模式来保证全局唯一性,避免多次创建和销毁数据库连接。

        3.3 日志管理器

        在项目中使用日志管理器来统一管理日志的输出和记录。日志管理器往往使用单例模式来保证全局唯一性,以便在整个项目中方便地使用和管理日志。

        3.4 配置管理器

        在项目中使用配置管理器来统一管理项目的配置信息。配置管理器往往使用单例模式来保证全局唯一性,方便在整个项目中获取和修改配置信息。

        3.5 缓存管理器

        在项目中使用缓存管理器来统一管理缓存数据。缓存管理器往往使用单例模式来保证全局唯一性,以便在整个项目中共享缓存数据。

        3.6 窗口管理器

        在GUI应用程序中使用窗口管理器来管理窗口的创建、销毁和切换等操作。窗口管理器往往使用单例模式来保证全局唯一性,方便在整个应用程序中管理窗口的状态。

四、单例模式的实现与讲解

        4.1 故事背景

        悟空和猪八戒一起前往蟠桃园,发现了许多美味的蟠桃。两人都非常喜欢吃蟠桃,于是开始争夺。悟空利用他的武力优势,想要把所有的蟠桃都夺走。而猪八戒则凭借他的速度优势,想要抢先吃到更多的蟠桃。这时,唐僧看出两人之间的争斗会导致不必要的麻烦,决定采用单例模式来解决这个问题。他告诉悟空和猪八戒,蟠桃园中的蟠桃树每年只能结一次果实,而且每次只有一颗蟠桃。他们只能通过团结合作,才能每人分到一部分的蟠桃。悟空和猪八戒被唐僧的建议所感动,决定放弃争夺,开始团结合作。他们一起控制自己的贪念,每次只摘下一颗蟠桃,然后平均分给自己和其他人。

        4.2 模式实现

                唐僧类实现单例模式

 /// <summary>
 /// 定义唐僧类
 /// </summary>
 public class TangSeng
 {
     // 唐僧实例
     private static TangSeng instance;

     // 私有的构造函数,防止外部实例化
     private TangSeng() { }

     /// <summary>
     /// 获取唐僧实例的方法
     /// </summary>
     /// <returns></returns>
     public static TangSeng GetInstance()
     {
         // 使用双重锁定确保线程安全
         if (instance == null)
         {
             lock (typeof(TangSeng))
             {
                 if (instance == null)
                 {
                     instance = new TangSeng();
                 }
             }
         }

         return instance;
     }

     /// <summary>
     /// 分享蟠桃的方法
     /// </summary>
     /// <param name="peachCount">蟠桃总数量</param>
     /// <param name="memberCount">每个人分到的蟠桃数量</param>
     public void SharePeach(int peachCount, int memberCount)
     {
         int eachPeachCount = peachCount / memberCount;
         Console.WriteLine("每个人分到的蟠桃数量:" + eachPeachCount);
     }
 }

                孙悟空类实现单例模式

 /// <summary>
 /// 定义孙悟空类
 /// </summary>
 public class SunWuKong
 {
     // 悟空实例
     private static SunWuKong instance;

     // 私有的构造函数,防止外部实例化
     private SunWuKong() { }

     // 获取悟空实例的方法
     public static SunWuKong GetInstance()
     {
         // 使用双重锁定确保线程安全
         if (instance == null)
         {
             lock (typeof(SunWuKong))
             {
                 if (instance == null)
                 {
                     instance = new SunWuKong();
                 }
             }
         }

         return instance;
     }

     // 争夺蟠桃的方法
     public void GrabPeach(int peachCount)
     {
         Console.WriteLine("悟空争夺到的蟠桃数量:" + peachCount);
     }
 }

                猪八戒类实现单例模式

   /// <summary>
   /// 定义猪八戒类
   /// </summary>
   public class ZhuBajie
   {
       // 猪八戒实例
       private static ZhuBajie instance;

       // 私有的构造函数,防止外部实例化
       private ZhuBajie() { }

       // 获取猪八戒实例的方法
       public static ZhuBajie GetInstance()
       {
           // 使用双重锁定确保线程安全
           if (instance == null)
           {
               lock (typeof(ZhuBajie))
               {
                   if (instance == null)
                   {
                       instance = new ZhuBajie();
                   }
               }
           }

           return instance;
       }
       // 争夺蟠桃的方法
       public void GrabPeach(int peachCount)
       {
           Console.WriteLine("猪八戒争夺到的蟠桃数量:" + peachCount);
       }
   }

                主函数调用

  public static void Main(string[] args)
  {
      // 唐僧实例
      TangSeng tangSeng = TangSeng.GetInstance();
      // 悟空实例
      SunWuKong wukong = SunWuKong.GetInstance(); 
      // 猪八戒实例
      ZhuBajie zhuBajie = ZhuBajie.GetInstance(); 
      // 唐僧分享蟠桃
      tangSeng.SharePeach(10, 3); 
      // 悟空争夺蟠桃
      wukong.GrabPeach(5); 
      // 猪八戒争夺蟠桃
      zhuBajie.GrabPeach(3);
  } 

                控制台输出结果

        4.3 模式讲解

        在上述代码中,我们首先定义了 TangSengSunWuKong和 ZhuBajie 这三个类。它们都有一个私有的静态实例变量,用来存储唯一的实例。

        接下来,我们定义了一个私有的构造函数,防止外部直接实例化这些类的对象。

        然后,我们使用双重锁定来实现线程安全的实例获取方法,也就是 GetInstance 方法。在这个方法中,首先检查实例变量是否为空,如果是,则进入临界区代码块。在临界区内部,再次检查实例变量是否为空,以确保在多线程环境下只有一个线程创建实例。如果为空,我们就创建新的实例并将其赋值给实例变量。最后,返回实例变量。

        在 TangSeng 类中,我们还定义了一个 SharePeach 方法来模拟唐僧分享蟠桃的场景。该方法接收两个参数,分别是蟠桃的总数和人数。根据总数和人数计算出每个人分到的蟠桃数量,并输出到控制台。

        在 SunWuKong类和 ZhuBajie 类中,我们也定义了类似的方法 GrabPeach 来模拟悟空和猪八戒争夺蟠桃的场景。这些方法接收一个参数,即争夺到的蟠桃数量,并将其输出到控制台。

        在 Main 函数中,我们首先通过调用 TangSeng.GetInstance()SunWuKong.GetInstance() 和 ZhuBajie.GetInstance() 来获取唐僧、悟空和猪八戒的实例。

        然后,我们分别调用唐僧的 SharePeach 方法,悟空的 GrabPeach 方法和猪八戒的 GrabPeach 方法来模拟故事中的场景。

        执行程序时,控制台会输出每个人分到的蟠桃数量、悟空争夺到的蟠桃数量和猪八戒争夺到的蟠桃数量。

五、单例模式需要注意的地方

        5.1 线程安全

        在多线程环境下,确保只有一个实例被创建。可以采用双重检查锁定、静态初始化、枚举等方式来实现线程安全。

        5.2 私有构造函数

        通过将构造函数声明为私有,可以防止外部直接实例化对象,只能通过单例模式提供的获取实例的方法获取对象。

        5.3 延迟加载

        单例对象的初始化可以延迟到第一次使用时进行,而不是在程序启动时即创建实例。

        5.4 序列化与反序列化

        如果单例类需要支持序列化和反序列化,需要注意在反序列化时是否会创建出新的实例。可以通过实现 ISerializable 接口或者添加 readResolve() 方法来防止反序列化时创建新的实例。

        5.5 全局访问点

        单例模式提供了一个全局访问点,可以在任何地方获取到唯一的实例。但也需要注意是否滥用单例模式,因为全局访问点可能会导致代码耦合性增加。

        5.6 单元测试

        单例模式在进行单元测试时可能会存在一些困难,因为它们具有全局状态。可以通过模拟或替代单例对象来解决这个问题。

        5.7 防止反射攻击

        通过在私有构造函数中增加防止多次实例化的判断,可以防止通过反射机制创建新的实例。

        5.8 生命周期管理

        单例对象的生命周期通常与整个应用程序的生命周期相同,需要注意在适当的时候释放资源。

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值