作为对象的创建模式,单例模式确保某哦一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
单例模式结构
很显然单例模式的要点有三个:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其它对象提供这个实例。
饿汉式单例类
饿汉式单例类是在Java语言里实现起来最为简便的单例类,下图所示的类图描述了一个饿汉式单例类的典型实现:
public class EagerSingleton {
private static final EagerSingleton m_instance = new EagerSingleton();
/**
* 私有默认构造方法
*/
private EagerSingleton() { }
/**
* 静态工厂方法
*/
public static EagerSingleton getInstance() {
return m_instance;
}
}
懒汉式单例类
与饿汉式单例类相同之处是,类的构造方法是私有的。与饿汉式单例类不同的是,懒汉式单例类在第一次被引用时将自己实例化。如果加载器是静态的,那么懒汉式单例类被加载时是不会将自己实例化的。如下图所示,类图中给出了一个典型的懒汉式单例类的实现。
public class LazySingleton {
private static LazySingleton m_instance = null;
/**
* 私有默认构造方法
*/
private LazySingleton() {}
/**
* 静态工厂方法,返回此类唯一实例
*/
public synchronized static LazySingleton getInstance() {
if(m_instance == null) {
m_instance = new LazySingleton();
}
return m_instance;
}
}
登记式单例类
登记式单例类是为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。它的实例化方式是饿汉式,它的子类实例化方式只能是懒汉式的,这是无法改变的。如下图所示,是登记式单例类的一个例子,图中关系线表明此类已将自己实例化。
public class RegSingleton {
private static HashMap m_registry = new HashMap();
static {
RegSingleton x = new RegSingleton();
m_registry.put(x.getClass().getName(), x);
}
/**
* 保护的默认构造方法
* /
protected RegSingleton(){}
/**
* 静态工厂方法,返回此类唯一实例
*/
public static RegSingleton getInstance(String name) {
if(name == null) {
name = "com.javapatterns.singleton.demos.RegSingleton";
}
if(m_registry.get(name)==null) {
try {
m_registry.put(name, Class.forName(name).newInstance());
} catch(Exception e) {
System.out.println("Error happend");
}
}
return (RegSingleton)(m_registry.get(name));
}
/**
* 一个示例性的商业方法
*/
public String about() {
return "Hello I am RegSingleton";
}
}
它的子类RegSingletonChild需要父类的帮助才能实例化。下图所示是登记式单例类子类的一个例子,图中的关系表明此类是由父类将子类实例化的:
public class RegSingletonChild extends RegSingleton {
public RegSingletonChild() {}
/**
* 静态工厂方法,返回此类唯一实例
*/
public static RegSingletonChild getInstance() {
return (RegSingletonChild)RegSingleton.getInstance("com.javapatterns.demos.RegSingletonChild");
}
/**
* 一个示例性的商业方法
*/
public String about() {
return "Hello I am RegSingletonChild";
}