设计模式之单例

简介: 设计模式之单例

单例模式介绍


679140-20210815232611339-327854217.png


单例模式主要解决的是,一个全局使用的类频繁的创建和消费,从而提升整体代码的性能。


在我们平时使用中,要确保一个类只能有一个实例对象,即使多线程同时访问,也只能创建一个实例对象,并需要提供一个全局访问此实例的点。


用来创建独一无二的,只能有一个实例对象的入场卷。


单例模式允许在程序的任何地方访问特定对象,但是它可以保护该实例不被其他代码覆盖。


使用场景:


  • 控制某些共享资源的访问权限(连接数据库、访问特殊文件)


  • 某些全局的属性或变量想保持其唯一性,可使用


  • 程序中的某个类对于所有客户端只有一个可用的实例,可以使用单例模式


679140-20210815232631663-757993809.png


代码结构:


  • 将默认的构造函数设为私有,防止其他对象使用单例类的new运算符。


  • 会有一个静态构造方法作为构造函数。该函数会偷偷调用私有构造函数来创建对象,并将其保存在一个静态成员变量中。后面所有对该函数的调用都将返回这一缓存对象。


实现方式:


  • 在类中声明一个私有静态成员变量用于保存单例模式


  • 声明一个公有静态构建方法用于获取单例


  • 在静态方法中实现“延迟初始化”,该方法会在首次被调用时创建一个新对象,并将其存储在静态成员变量中,此后该方法每次被调用时都返回该实例


  • 将类的构造函数私有私有,防止其外部对象声明调用



单例模式优缺点


优点:


  • 可以保证一个类只有一个实例


  • 获得了一个指向该实例的全局访问节点


  • 仅在首次请求单例对象时对其进行初始化


缺点:


  • 违反了“单一职责原则”(该模式同时解决了两个问题)


  • 该模式在多线程中需特殊处理,避免多个线程多次创建单例对象


  • 单元测试比较困难,无法新建声明新的测试对象。


Demo


单例可以分很多实现方式,但是从大类上来划分,主要为懒汉模式和饿汉模式



懒汉模式
  • 懒汉模式(线程不安全)
  /// <summary>
    /// 单例模式 (常规用法,线程不安全。)
    /// </summary>
    public class Singleton
    {       
        /// <summary>
        /// 私有构造函数
        /// </summary>
        private Singleton()
        {
        }
        /// <summary>
        /// 静态局部变量
        /// </summary>
        private static Singleton _instance=null;
        /// <summary>
        /// 静态的全局唯一访问口
        /// 只能得到缓存的静态局部变量实例,无法重新新建。
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance() 
        {
            if (_instance==null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }


此方法满足了懒加载,但是如果多个访问者同时进行访问获取对象,就会出现多个实例对象,就不是单例模式了,所以此方法在多线程场景是不实用的。


  • 懒汉模式(线程安全)
 /// <summary>
    /// 单例模式 (常规用法,线程安全。)
    /// </summary>
    public class Singleton
    {       
        /// <summary>
        /// 私有构造函数
        /// </summary>
        private Singleton()
        {
        }
        /// <summary>
        /// 静态局部变量
        /// </summary>
        private static Singleton _instance=null;
        /// <summary>
        /// 声明锁 锁同步
        /// </summary>
        private static readonly object _lock = new object();
        /// <summary>
        /// 静态的全局唯一访问口
        /// 只能得到缓存的静态局部变量实例,无法重新新建。
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance(string value) 
        {  
                if (_instance == null)                //双重判空,确保在多线程状态下只创建一个实例对象
                {
                    lock (_lock)                                 //加锁,确保其每次只能由一个对象进行访问
                    {
                        if (_instance==null)
                        {
                            _instance = new Singleton();
                            _instance.Value = value;
                        }
                    }                    
                }            
            return _instance;
        }
        public string Value { get; set; }
    }



   class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("多线程进行访问");
            Thread processOne = new Thread(() => {
                TestSingleton("阿辉");
            });
            Thread processTwo = new Thread(() => {
                TestSingleton("阿七");
            });
            processOne.Start();
            processTwo.Start();
            processOne.Join();
            processTwo.Join();
            Console.ReadKey();
        }
        static void TestSingleton(string value) 
        {
            Singleton s = Singleton.GetInstance(value);
            Console.WriteLine(s.Value);
        }
    }


679140-20210815232706445-61301345.png

可以看到在我们模拟的多线程访问过程中,即使设置的阿辉和阿七,最后输出的也只有阿辉,也就是说只能创建一个实例对象。


可以看到懒加载就是程序刚开始不实例化,只有在被调用或者需要使用它的时候才进行实例化操作,这就是懒加载。


饿汉模式


  • 使用静态变量实现单例  ------饿汉模式(线程安全)
 public class Singleton1
    {
        /// <summary>
        /// 饿汉式,也就是在程序运行时都已经进行了初始化操作,后续只是调用而已。
        /// </summary>
        private static Singleton1 instance = new Singleton1();
        private Singleton1()
        {
        }
        public static Singleton1 GetInstance() 
        {
            return instance;
        }                   
    }


饿汉式顾名思义就是提前都恶的不行了,在程序刚开始启动的时候就已经将其进行了实例化,后续只管调用。


这种不是懒加载,无论程序是否会用到这个类,它都会提早的进行实例化。


  • 利用静态构造函数实现单例模式(线程安全)
  public class Singleton2 
    {
        private static Singleton2 _Singleton2 = null;
        static Singleton2() {
            _Singleton2 = new Singleton2();
        }
        public static Singleton2 CreateInstance() 
        {
            return _Singleton2;
        }
    }



单例模式常用的就大体介绍完了,我们在平时的使用过程中需要根据不同的业务逻辑来选择不同的实现方式,不能说哪一种最好,也不能说哪一种不好,只是它们使用的场景不同而已。


目录
相关文章
|
25天前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
59 0
|
1月前
|
设计模式 缓存 安全
单例设计模式的优缺点
单例设计模式的优缺点
30 0
|
1月前
|
设计模式 XML 存储
关于 ABAP 单例设计模式的一个冷门知识点
关于 ABAP 单例设计模式的一个冷门知识点
20 0
|
1月前
|
设计模式 安全 Java
【设计模式】2、设计模式分类和单例设计模式
【设计模式】2、设计模式分类和单例设计模式
24 0
|
1月前
|
设计模式 Java
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
28 2
|
3月前
|
设计模式 消息中间件 安全
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
34 1
|
3月前
|
设计模式 安全 Java
最简单的设计模式是单例?
单例模式可以说是Java中最简单的设计模式,但同时也是技术面试中频率极高的面试题。因为它不仅涉及到设计模式,还包括了关于线程安全、内存模型、类加载等机制。所以说它是最简单的吗?
56 3
最简单的设计模式是单例?
|
21天前
|
设计模式 安全 Java
在Java中即指单例设计模式
在Java中即指单例设计模式
15 0
|
5月前
|
设计模式 存储
static应用之 单例设计模式(饿汉单例&懒汉单例)
本章我们来学习单例模式中的饿汉单例和懒汉单例,那么什么是单例模式呢?应用该模式的这个类永远只有一个实列,即一个类只能创建一个对象例如电脑上的任务管理器对象只需要一个就能解决问题,可以节省内存空间先定义一个类,把构造器私有如下图,先来看一下没有把构造器私有化的SingleInstance类,此时Test类中可以随意创建多个SingleInstance的实例化。 在SingleInstance类中用private修饰无参构造器,此时左边new方法报错了。我们在右边创建一个静态变量来存储对象,变量名为instan
24 0
|
6月前
|
设计模式 安全 Java
【设计模式】单例设计模式
1、前言 单例模式是一种设计模式,它确保一个类只能创建一个实例,并提供一种全局访问这个实例的方式。在Java中,单例模式可以通过多种方式来实现,其中最常见的是使用私有构造函数和静态方法实现
33 0