单例模式

作为对象的创建模式,单例模式确保某一类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类。单例类的一个重要特点是它的构造方法是私有的,且此类不能被继承。它有如下几种结构:

1、饿汉式

饿汉式单例类是当这个类被加载时就被实例化

  1. public class EagerSingleton {  
  2.  
  3.     public static EagerSingleton eagerInstance = new EagerSingleton();  
  4.  
  5.     private EagerSingleton() {  
  6.     }  
  7.  
  8.     public static EagerSingleton getInstance() {  
  9.         return eagerInstance;  
  10.     }  

饿汉式单例类可以在Java语言里实现,不易在C++内实现,因为静态初始化在C++里没有固定的顺序,因而静态的eagerInstance变量初始化与类的加载顺序没有保证,这更符合Java语言的特点。

2、懒汉式

与饿汉式单例类不同的是,懒汉式单例类在第一次被引用时才将自己实例化。

  1. public class LazySingleton {  
  2.  
  3.     private static LazySingleton lazyInstance = null;  
  4.  
  5.     private LazySingleton() {  
  6.     }  
  7.  
  8.     public synchronized static LazySingleton getInstance() {  
  9.         if (lazyInstance == null) {  
  10.             lazyInstance = new LazySingleton();  
  11.         }  
  12.         return lazyInstance;  
  13.     }  

上面给出懒汉式单例类实现里对静态方法使用了同步化,以适应多线程环境。

3、登记式

登记式单例类是为了克服上面两种单例类均不能被继承的缺点而设计的,它的子类实例化的方式只能是懒汉式的。

  1. package com.wgy.javapatterns.singleton;  
  2.  
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.  
  6. public class RegSingleton {  
  7.  
  8.     private static Map registry = new HashMap();  
  9.     static {  
  10.         RegSingleton regInstance = new RegSingleton();  
  11.         registry.put(regInstance.getClass().getName(), regInstance);  
  12.     }  
  13.  
  14.     protected RegSingleton() {  
  15.     }  
  16.       
  17.     public static RegSingleton getInstance(String name) {  
  18.         if (name == null) {  
  19.             name = "com.wgy.javapatterns.singleton.RegSingleton";  
  20.         }  
  21.         if (registry.get(name) == null) {  
  22.             try {  
  23.                 registry.put(name, Class.forName(name).newInstance());  
  24.             } catch (Exception e) {  
  25.                 System.out.println("Error happened!");  
  26.             }  
  27.         }  
  28.         return (RegSingleton) registry.get(name);  
  29.     }  
  30.       
  31.     public String sayHi() {  
  32.         return "Hello, I am RegSingleton!";  
  33.     }  
  34. }  

它的子类RegSingletonChild需要父类的帮助才能实例化,示例代码如下:

  1. package com.wgy.javapatterns.singleton;  
  2.  
  3. public class RegSingletonChild extends RegSingleton {  
  4.  
  5.     public RegSingletonChild() {  
  6.     }  
  7.       
  8.     public static RegSingletonChild getInstance() {  
  9.         return (RegSingletonChild) RegSingleton  
  10.                 .getInstance("com.wgy.javapatterns.singleton.RegSingletonChild");  
  11.     }  
  12.       
  13.     public String sayHi() {  
  14.         return "Hello, I am RegSingletonChild!";  
  15.     }  

本例中加入了getInstance()方法,好处是RegSingletonChild可以通过这个方法返回自己的实例,缺点是由于数据类型不同,无法在RegSingleton提供这样一个方法。

登记式单例类的缺点:由于子类必须允许父类以构造方法产生实例,因此它的构造方法必须是公开的,这等于允许了以这种方式产生实例而不在父类的登记中;由于父类的实例必须存在才可能有子类的实例,这在有些情况下是种浪费。