单态模式
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机
该模式较常见也是使用最频繁的设计模式之一。单态模式的主要作用是保证在JAVA应用程序中某些特定的类只有一个实例存在。
该模式的好处: 节省内存及系统开销,使用合适的中间件(.NET Remoting),可以把SINGLETON模式扩展为跨多个CLR或多个计算机工作。任何类都可以方便的转换为SINGLETON模式。只在第一次使用时进行创建。并且它由于限制了实例个数,有利于垃圾回收。
缺点:不能继承、效率问题、调用不透明(调用者知道自己在调用谁)
示例:
常用于数据库访问、单点登录等。下面的代码演示了常用的单态模式的写法:
一般Singleton模式通常有几种形式:
public class Singleton {//1.私有的构造子(构造器,构造函数,构造方法)
private Singleton() { //通过添加一个私有构造函数以避免外部程序自行实例化该对象 //注意这是private 只供内部调用
}
//2.私有,静态的类自身实例
private final Singleton instance = new Singleton();
//3.公开,静态的工厂方法
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() { return instance; } public void hello() { System.out.println("hello sinory"); } }
使用Singleton.getInstance()可以访问单态类。
Singleton obj = Singleton.getInstance();
这个单例类在自身被加载时instance会被实例化,即便加载器是静态的。因此,对于资源密集,配置开销较大的单体更合理的做法是将实例化(new)推迟到使用它的时候。即惰性加载(Lazy loading),它常用于那些必须加载大量数据的单体。修改下
class LazySingleton { //初始为null,暂不实例化 private static LazySingleton instance = null; //私有的构造子(构造器,构造函数,构造方法) private LazySingleton(){} //公开,静态的工厂方法,需要使用时才去创建该单体 public static LazySingleton getInstance() { if( instance == null ) { instance = new LazySingleton(); } return instance; } }
上面第二中形式是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。
注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴趣者进一步研究。
一般认为第一种形式要更加安全些。
- 一是某个类只能有一个实例;
- 二是它必须自行创建这个实例;
- 三是它必须自行向整个系统提供这个实例。
- 一是单例模式的类只提供私有的构造函数,
- 二是类定义中含有一个该类的静态私有对象,
- 三是该类提供了一个静态的共有的函数用于创建或获取它本身的静态私有对象。