本次实例介绍了单例设计模式里最常见的两个实例——饿汉单例与懒汉单例。
1. 类图
2. Java实现代码
package cn.edu.ynu.sei.singleton;
/**
* “饿汉式”的单例类
*
* @author 88250
* @version 1.0.0, 2007-8-17
*/
public class EagerSingleton
{
/**
* 单一实例
*
* @uml.property name="instance" readOnly="true"
*/
private static final EagerSingleton instance = new EagerSingleton();
/**
* 私有的默认构造器
*/
private EagerSingleton()
{
}
/**
* 静态工厂方法
*
* @return Returns the instance.
*/
public static EagerSingleton getInstance()
{
return null;
}
}
/**
* “饿汉式”的单例类
*
* @author 88250
* @version 1.0.0, 2007-8-17
*/
public class EagerSingleton
{
/**
* 单一实例
*
* @uml.property name="instance" readOnly="true"
*/
private static final EagerSingleton instance = new EagerSingleton();
/**
* 私有的默认构造器
*/
private EagerSingleton()
{
}
/**
* 静态工厂方法
*
* @return Returns the instance.
*/
public static EagerSingleton getInstance()
{
return null;
}
}
package cn.edu.ynu.sei.singleton;
/**
* “懒汉式”单例
*
* @author 88250
* @version 1.0.0, 2007-8-17
*/
public class LazySingleton
{
/**
* 单一实例
*
* @uml.property name="instance"
*/
private static LazySingleton instance;
/**
* 私有的默认构造器
*/
private LazySingleton()
{
}
/**
* 静态工厂方法
* @return Returns the instance.
* @uml.property name="instance"
*/
public static LazySingleton getInstance()
{
if (instance == null)
{
instance = new LazySingleton();
}
return instance;
}
}
/**
* “懒汉式”单例
*
* @author 88250
* @version 1.0.0, 2007-8-17
*/
public class LazySingleton
{
/**
* 单一实例
*
* @uml.property name="instance"
*/
private static LazySingleton instance;
/**
* 私有的默认构造器
*/
private LazySingleton()
{
}
/**
* 静态工厂方法
* @return Returns the instance.
* @uml.property name="instance"
*/
public static LazySingleton getInstance()
{
if (instance == null)
{
instance = new LazySingleton();
}
return instance;
}
}
3. 总结
这里只是介绍了最简单的例子,单例模式中还有一种叫做“登记式”单例的模式,这种模式克服了以上两种单例均不能继承的缺点。有兴趣的话可以自己查查相关资料,这里不再赘述。这里我们简述一下关于在分布式系统和多线程环境下使用单例模式应该注意的问题。在分布式系统中,设计的单例类可能会在不同的JVM中被实例化,那就相当于单例模式在全局看来有了多个实例。这个时候需要注意的是,如果这个单例是无状态的,那么是没有什么问题的。但是,如果这个单例是有状态的,那就会造成一定的问题。举例来说,如果一个单例对象可以持有一个int类型的属性,用来给一个系统提供一个数值唯一的序列号,作为某个贩卖系统的帐单号码的话,用户将会看到同一个号码出现好几次。所以,在任何使用了EJB、RMI和JINI等技术的分布式系统中,应当避免使用有状态的单例模式。
而在多线程环境下,必须注意使用关键字synchronized同步化getInstance方法。如果你是一个有经验的C/C++程序员,可能会使用“双重检查成例”的代码模式去解决这个问题,但是,这个代码级的模式在Java里是完全不能成立的。关于“双重检查成例”的问题请参考《Java与设计模式》以及[BLOCH01, GOETZ01, DCL01]。
所以抽象工厂只是在一定程度上支持OCP的,在设计的时候这点很值得我们注意。