设计模式之单例

简介: 设计模式之单例

单例模式介绍


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;
        }
    }



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


目录
相关文章
|
6月前
|
设计模式
单例设计模式步骤
单例设计模式步骤
34 1
|
6月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
142 0
|
6月前
|
设计模式 安全 Java
最简单的设计模式是单例?
单例模式可以说是Java中最简单的设计模式,但同时也是技术面试中频率极高的面试题。因为它不仅涉及到设计模式,还包括了关于线程安全、内存模型、类加载等机制。所以说它是最简单的吗?
80 3
最简单的设计模式是单例?
|
6月前
|
设计模式 安全 Java
【设计模式】2、设计模式分类和单例设计模式
【设计模式】2、设计模式分类和单例设计模式
58 0
|
6月前
|
设计模式 消息中间件 安全
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
60 1
|
6月前
|
设计模式 Java
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
56 2
|
6月前
|
设计模式 安全 Java
在Java中即指单例设计模式
在Java中即指单例设计模式
40 0
|
2月前
|
设计模式 存储 安全
设计模式——设计模式介绍和单例设计模式
饿汉式(静态常量)、饿汉式(静态代码块)、懒汉式(线程不安全)、懒汉式(线程安全,同步方法)、懒汉式(线程不安全,同步代码块)、双重检查(推荐,线程安全、懒加载)、静态内部类(推荐)、枚举(推荐)
设计模式——设计模式介绍和单例设计模式
|
3月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
52 1
|
6月前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式