浅谈23种设计模式(单例模式)

5 篇文章 0 订阅
2 篇文章 0 订阅

浅谈23种设计模式(java版)

单例模式


  • 什么是设计模式

    • 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结,使用设计模式的目的是为了提高代码的可重用性,使得代码更加符合人类的理解思维。
  • 什么是单例模式

    • 单例顾名思义在整个系统中只有一个类的实例对象。
  • 这有什么好处

    • 有一些对象我们确实只需要一个,例如,线程池,缓存,对话框,日志对象等等,就只能有一个实例,如果创建多个实例,就会导致许多问题,例如程序运行异常,运行结果不一致等问题。
  • 不简单的单例模式

    • 虽然单例模式听起来简单易懂,但是真正想实现一个单例模式也不是那么容易的,如何保证一个对象只能实例化一次,如何保证多线程下的线程安全问题等等。
  • 接下来让我们一步一步的来实现单例模式

    • 如何创建一个对象?

      new Singleton();

    • 如果其它对象想创建Singleton会怎么样? 可以再次创建吗?

      是的,当然可以

    • 如果有一个类我们是否可以多次实例化它?

      答案是:当然可以了, 只要你的类是公开的

    • 如果不公开类会怎么样?

      如果不公开类,那只有同一个包内的类可以实例化它,并可以实例化多次(小伙子你好抠)

    • 我们可以让外部无法实例化它吗?

      当然可以了,如果我们把它的构造方器定义为私有的,除了它的内部类可以初始化它,其它对象都不能初始化它,当然也就不能实例化它(让人活不了)

        public Singleton{
            private Singleton(){ }
        }
      
    • 我觉得私有构造器是不是有点不合理?

      没错确实有点不合理,因为我们必须有Singleton类的实例才可以调用该类的构造器,但没有类能实例化它,所以我们得不到它的实例,这就好比 “鸡生蛋,蛋生鸡”,我们只能在类内部调用构造器。

    • 我有个想法你认为如何?

      如果我们在类的内部创建一个静态方法去调用它如何。

       public Singleton{
            private Singleton(){ }
            public static Singleton getInstance(){
            }
       }
      
    • 为什么 调用getInstance() 不用对象名而用类名?

      因为getInstance()方法是静态的,静态方法是属于类而非属于对象的,所以调用它只能用类名。

    • 有意思,如果把上面的组合在一起会如何?

      我们就能够在getInstance()方法中愉快的进行实例的创建了。

      public Singleton{
           private Singleton(){ }
           public static Singleton getInstance(){
               return new Singleton();
         }
      } 
      
    • 我们是否解决了实例化问题?

      对,我们已经可以实例化对象了,但也仅仅是实例化对象,并没有保证对象唯一。

    • 如何保证对象的唯一性?

      我们改造一下上面的代码

       //懒汉模式 
       public Singleton{
            //保存实例化的对象
            private static Singleton  singleton = null;
            private Singleton(){ }
            public static Singleton getInstance(){
               if(singleton == null){
                    return new Singleton();
               }
               else{
                    return singleton;
               }
          }
      } 
      
          //饿汉模式
           public Singleton{
           //类加载时候就创建对象(因为是静态变量所以只加载一次保证了实例唯一)
           private static Singleton  singleton = new Singleton()l;
           private Singleton(){ }
           public static Singleton getInstance(){				     
                   return singleton;				 
         }
      } 
      

      以上两种模式创建单例对象。

    • 有个问题出现了如果在多线程情况下会如何?

      我们发现在懒汉模式下可能会出现多个线程创建多个实例的情况,这就违背了我们单例原则了。

    • 如何解决多线程下的安全问题?

      使用synchronized 关键字同步代码块

         //懒汉模式 
        public Singleton{
             //保存实例化的对象
             private static Singleton  singleton = null;
             private Singleton(){ }
             //加入同步关键字使得同一时间只能有一个线程实例化该类
             public static synchronized Singleton getInstance(){
                if(singleton == null){
                     return new Singleton();
                }
                else{
                     return singleton;
                }
           }
       }    
      

      但是我们只有第一次执行才会同步,显然上面的每次执行都同步影响效率

    • 我们如何改善多线程?

      使用双重锁 首先检查实例是否创建,如果未创建才会同步,并且只有第一次同步。

          //懒汉模式 
        public Singleton{
             //使用volatile关键字 保证当Single 创建时,多线程能正确处理
             private volatile static Singleton  singleton = null;
             private Singleton(){ }
             //加入同步关键字使得同一时间只能有一个线程实例化该类
             public static Singleton getInstance(){
                if(singleton == null){
                      synchronized (Singleton.class){
                           if(singleton == null){
                               singleton = new Singleton();
                           }
                      }			              
                }
                return singleton;
           }
       }  
      
    • 总结

      看到这里是不是在想单例也不是那么容易创建的,需要考虑如何保证唯一实例,多线程下如何保证实例唯一,如何优化多线程等等,但是只要我们一步一步的学习,不要操之过急,认真思考,多加练习,再难的设计模式也能学会后续我会加入工厂模式继续优化单例的创建

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值