美文网首页Java 杂谈
设计模式-单例模式

设计模式-单例模式

作者: breezedancer | 来源:发表于2016-10-28 15:12 被阅读0次

    单例模式有3个特点:一是某个类在某个上下文当中有且仅有一个实例;二是这个实例是自己创造出来的,别的类不好代办;三是在整个系统当中他必须能够提供这个单例。

    可以得出单例的类必须包含自己的一个静态属性,自己的构造方法为私有,确保外界无法实例化,提供一个静态方法,该方法实例化静态属性并且向外提供这个实例。

    他的 UML 图如下:


    该模式的使用条件是在环境下只需一个实例,就可以使用该模式;比如在现今中国(环境),说国家主席这个类就自然想到习大大,那么这个就是单例模式,所有需要国家主席解决的都到习大大这里,没有第二个。

    单例最简单的实现如下代码:

    public class Singleton {  
      private static Singleton instance;  
      private Singleton (){}   
      public static Singleton getInstance() {  
      if (instance == null) {  
       instance = new Singleton();  
      }  
      return instance;  
      }  
    }  
    

    这个属于懒汉模式,需要实例化的找我,但是也是线程不安全的;同时有2个线程同时调用 getInstance 方法可能会各自实例化各自的单例,这就不对了。改进下,把方法修改为public static synchronized Singleton getInstance()增加同步块,可能每次都同步下又有性能丢失。

    那么这次把实例化放到类装载时看看,就形成了饿汉模式,迫不及待的先行实例化

    public class Singleton {  
         private static Singleton instance = new Singleton();  
         private Singleton (){}
         public static Singleton getInstance() {  
         return instance;  
         }  
    }  
    

    这个没有达到懒加载,我压根在环境里就不需要你这个单例,你给实例化出来干什么呢?或者有其他的情况导致类加载也会出现问题。

    再进行改变,使用内部类

    public class SingletonClass {
        private SingletonClass() {
        }
        public static SingletonClass getInstance() {
            return SingletonInnerClass.sc;
        }
        private static class SingletonInnerClass {
            private static SingletonClass sc = new SingletonClass();
        }
    }
    

    这个方式是即使父类实例化了,内部类也不一样实例化,只有显示调用 getInstance 才可以显示装载内部类,从而达到实例化的效果。

    使用枚举类来实现,是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

    enum Singleton {  
      INSTANCE;  
      public static Singleton getInstance() {  
        return INSTANCE;  
      }  
    } 
    

    最后是双重检验来实现,确保唯一实例

    public class DoubleCheckedLockingSingleton{
         private volatile DoubleCheckedLockingSingleton INSTANCE;
         private DoubleCheckedLockingSingleton(){}
         public DoubleCheckedLockingSingleton getInstance(){
             if(INSTANCE == null){
                synchronized(DoubleCheckedLockingSingleton.class){
                    //双重检验单例模式
                    if(INSTANCE == null){
                        INSTANCE = new DoubleCheckedLockingSingleton();
                    }
                }
             }
             return INSTANCE;
         }
    }
    

    众多提倡的枚举类型,但在安卓开发过程中不太建议使用。单例模式使用频率非常高的一个模式,针对上面种种情况,需要各自筛选选用,并非都合适或不合适,尤其是最后的双重校验,在 java 编译器中,DoubleCheckedLockingSingleton类的初始化和INSTANCE变量赋值的顺序不可预料,有可能发生崩溃的危险。

    与单例对应的是多例模式,多例模式是单例模式的扩展版本,比如一个系统需要支持多国语言,每个语言就是一个实例,那么久需要对若干个国家语言实例化,但不能从外界去 new 操作实例化,仍然需要配合参数从该类获取特定的实例。其主要思路还是构造方法私有化,包括有参数的构造方法和无参数的构造方法都要私有化,仍然对外界提供实例,根据参数决定提供何种实例。

    相关文章

      网友评论

        本文标题:设计模式-单例模式

        本文链接:https://www.haomeiwen.com/subject/ieleuttx.html