zoukankan      html  css  js  c++  java
  • 我们真的会使用单例模式吗?

    这篇博客的标题用了一个疑问句,源于我们公司的代码评审,深刻的讨论了单例模式的使用场景及其与静态方法来说有何不同,这次讨论确实让我真正的理解了单例模式的使用,虽然说理解还一定全面,但必须作为一个认知的提升。告诉了我自己,对于编程,不懂的太多,原理性的东西还需要持续的学习。

    进入正文,我们来讨论一下,什么是单例模式,何时使用单例模式?

    单例模式是经典设计模式的一种,熟悉设计模式或者说读过设计模式相关书籍的同事都知道,这应该算是设计模式中最简单、最容易理解、使用最广泛的一种。单例模式主要是用来实现一个类的实例全局唯一,使用double check的形式来定义。

    
    
     1 public class SingleInstance
     2     {
     3         private static readonly object _lock = new object();
     4         private static SingleInstance _instance = null;
     5 
     6         /// <summary>
     7         /// 私有构造函数
     8         /// </summary>
     9         private SingleInstance() { }
    10 
    11         /// <summary>
    12         /// 单一实例
    13         /// </summary>
    14         /// <returns></returns>
    15         public static SingleInstance GetInstance()
    16         {
    17             if (_instance == null)
    18             {
    19                 lock (_lock)
    20                 {
    21                     if (_instance == null)
    22                     {
    23                         _instance = new SingleInstance();
    24                     }
    25                 }
    26             }
    27             return _instance;
    28         }
    29 
    30 
    31         public  void Show()
    32         {
    33             Console.WriteLine("输出。。。郭志奇");
    34         }
    35 
    36         public  void Speak()
    37         {
    38             Console.WriteLine("说话。。。郭志奇");
    39         }
    40     }
    
    
    单例模式使用了私有构造函数来保证外部无法实例化、使用double check来保证实例被唯一创建。这是一个基本的单例模式写法,我一般会在其中写一些方法来进行调用,主要是为了避免每次调用都需要new的麻烦。但其中存在一些问题,如果采用静态方法来写:
    1        public static void Show()
    2         {
    3             Console.WriteLine("输出。。。郭志奇");
    4         }
    5 
    6         public static void Speak()
    7         {
    8             Console.WriteLine("说话。。。郭志奇");
    9         }

    比较这两种调用,其实使用方式是一致的,但单例模式会在程序运行中一直存在,不会被销毁,因为单例模式中使用到了静态变量,静态变量的使用会导致实例不会被销毁。但这也不应该是单例模式的缺点。

    但我为什么会说我们真的懂单例模式?

    回到开头,我们说单例模式,为什么我们需要单例模式,绝对不是因为方便调用,因为静态方法更方便。那到底为什么使用单例模式呢?其实经过我们的讨论,单例模式的使用场景是一些全局不可变参数,可以放到单例中,比如从配置获取值,然后缓存到单例中,这才是我们应当使用单例的场景,千万别像我,为了使用方便而无节制的使用单例。

    使用单例,方便调用,但会造成什么问题呢?

    要回答这个问题,我们首先回忆一下GC的垃圾回收机制,垃圾回收分为三代,如果类中包含静态成员,垃圾回收机制是不会回收的,也就意味着如果我们无节制的使用单例,会造成程序运行过程中出现大量的实例不会被销毁,会无意识的造成内存使用增高。    如果采用懒加载的方式,在单例未被调用的时候,不会实例化,如果采用饿汉加载的话,那么在程序初始化的时候,就会被初始化,无疑会加重程序的初始化成本,增加启动时间。

    如果我们仅仅是为了方便调用,可以使用静态方法。

    上面我们说了懒加载方式,我们来代码说明一下饿汉模式的加载方式:

     1   public class SingleInstance
     2     {
     3         private static readonly object _lock = new object();
     4         private static SingleInstance _instance = new SingleInstance();
     5 
     6         /// <summary>
     7         /// 私有构造函数
     8         /// </summary>
     9         private SingleInstance() { }
    10 
    11         /// <summary>
    12         /// 单一实例
    13         /// </summary>
    14         /// <returns></returns>
    15         public static SingleInstance GetInstance()
    16         {            
    17             return _instance;
    18         }
    19 
    20 
    21         public void Show()
    22         {
    23             Console.WriteLine("输出。。。郭志奇");
    24         }
    25 
    26         public void Speak()
    27         {
    28             Console.WriteLine("说话。。。郭志奇");
    29         }
    30     }

    饿汉模式的加载就是静态成员在定义的时候即初始化。

    总结:

    1、我们应该选择合适的时机使用单例模式,不要无节制的使用,应该明白何时才应该使用单例模式。

    2、尽量避免静态成员的使用,因为静态成员所在的实例,不会被GC回收。

    3、优先选择静态方法调用而不是单例模式调用。

    4、如果必须使用单例模式,尽量采用懒加载,而不是饿汉加载的方式,减少程序启动成本。

    引申:

    1、我们使用了lock(object)来锁定一个变量,达到加锁的目的,避免多个线程同时对实例执行初始化。那么如果我们lock(string 字符串类型)是否可以呢?答案是否定。

    2、System.String和string有什么不同呢?

    欢迎有不同见解的同事可以回复讨论,知识总是在讨论中得到升华。

  • 相关阅读:
    力扣 227 :基本计算器(II)
    力扣 224 :基本计算器(I)
    力扣 888:公平的糖果棒交换(哈希表法)
    力扣 1047 :删除字符串中的所有相邻重复项
    力扣 1423 :可获得的最大点数
    vue+spreadjs+后台Java实现与服务端交互的导入导出
    webpack 中 require.context() 多个模块的加载
    dwd_fact_coupon_use
    dwd_fact_cart_info
    dwd_fact_order_detail
  • 原文地址:https://www.cnblogs.com/jiagoushi/p/8859746.html
Copyright © 2011-2022 走看看