在Java设计模式中,单例模式相对来说算是比较简单的一种构建模式。适用的场景在于:对于定义的一个类,在整个应用程序执行期间只有唯一的一个实例对象。如Android中常见的Application对象。
通过单例模式,自行实例化并向这个系统提供这个单一实例的访问方法。
根据此单一实例产生的时机不同(当然,都是指第一次,也是唯一一次产生此单一实例时),可以将其分为懒汉式、饿汉式和登记式。
一、懒汉式:
其特点是延迟加载,即当需要用到此单一实例的时候,才去初始化此单一实例。常见经典的写法如下:
1 package com.qqyumidi; 2 3 public class SingleTon { 4 5 // 静态实例变量 6 private static SingleTon instance; 7 8 // 私有化构造函数 9 private SingleTon() { 10 11 } 12 13 // 静态public方法,向整个应用提供单例获取方式 14 public static SingleTon getInstance() { 15 if (instance == null) { 16 instance = new SingleTon(); 17 } 18 return instance; 19 } 20 21 }
二、饿汉式:
饿汉式的特点是应用中尚未需要用到此单一实例的时候即先实例化。常见的经典写法为:
1 package com.qqyumidi; 2 3 public class SingleTon { 4 5 // 静态实例变量,直接初始化 6 private static SingleTon instance = new SingleTon(); 7 8 // 私有化构造函数 9 private SingleTon() { 10 11 } 12 13 // 静态public方法,向整个应用提供单例获取方式 14 public static SingleTon getInstance() { 15 return instance; 16 } 17 18 }
三、登记式单例模式:
登记式单例模式,一般是通过一个专门的类对各单例模式的此单一实例进行管理和维护。通过Map方式可以方便的实现此中目的。常见的代码如下:
1 package com.qqyumidi; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 public class SingleTonManager { 7 8 private static Map singleTonMap = new HashMap(); 9 10 public static void main(String[] args) { 11 // 获取A类的单例 12 A a = (A) getInstance(A.class.getName()); 13 // 获取B类的单例 14 B b = (B) getInstance(B.class.getName()); 15 } 16 17 // 根据类型获取单例 18 public static Object getInstance(String className) { 19 // 判断singleTonMap中是否有此单例,有则取得后返回,无则添加单例后返回 20 if (!singleTonMap.containsKey(className)) { 21 try { 22 singleTonMap.put(className, Class.forName(className).newInstance()); 23 } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 24 // TODO Auto-generated catch block 25 e.printStackTrace(); 26 } 27 } 28 return singleTonMap.get(className); 29 } 30 } 31 32 class A { 33 34 } 35 36 class B { 37 38 }
另外:需要注意的是,在多线程环境中,以上各种方法构造单例模式需要考虑到线程安全问题。
四、改进型懒汉式(直接满足线程安全)——通过静态内部类实现
在如上的懒汉单例模式中,对于多线程环境中。可以通过常见的如synchronized等方式实现线程安全,同时,可以通过Java静态内部类的方式实现进一步改进。
常见代码如下:
1 package com.qqyumidi; 2 3 public class SingleTon { 4 5 // 利用静态内部类特性实现外部类的单例 6 private static class SingleTonBuilder { 7 private static SingleTon singleTon = new SingleTon(); 8 } 9 10 // 私有化构造函数 11 private SingleTon() { 12 13 } 14 15 public static SingleTon getInstance() { 16 return SingleTonBuilder.singleTon; 17 } 18 19 public static void main(String[] args) { 20 SingleTon instance = getInstance(); 21 } 22 }
其主要原理为:Java中静态内部类可以访问其外部类的成员属性和方法,同时,静态内部类只有当被调用的时候才开始首次被加载,利用此特性,可以实现懒汉式,在静态内部类中静态初始化外部类的单一实例即可。