Java 杂谈

设计模式-单例模式

2016-10-28  本文已影响0人  breezedancer

单例模式有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 操作实例化,仍然需要配合参数从该类获取特定的实例。其主要思路还是构造方法私有化,包括有参数的构造方法和无参数的构造方法都要私有化,仍然对外界提供实例,根据参数决定提供何种实例。

上一篇下一篇

猜你喜欢

热点阅读