在 Java 中应用设计模式 -- Singleton
http://www.ibm.com/developerworks/cn/java/designpattern/singleton/
?
?
回页首
具体实施
实现 Singleton 模式的办法通常有三种.
一. 用静态方法实现 Singleton这种方法是使用静态方法来监视实例的创建.为了防止创建一个以上的实例,我们最好把构造器声明为private.
这样可以防止客户程序员通过除由我们提供的方法之外的任意方式来创建一个实例,如果不把构造器声明为private,编译器就会自作聪明的自动同步一个默认的friendly构造器.这种实现方法是最常见的,也就是图1中结构的标准实现.
public class Singleton { private static Singleton s; private Singleton(){}; /** * Class method to access the singleton instance of the class. */ public static Singleton getInstance() { if (s == null) s = new Singleton(); return s; }}// 测试类class singletonTest { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); if (s1==s2) System.out.println("s1 is the same instance with s2"); else System.out.println("s1 is not the same instance with s2"); }}
?
singletonTest运行结果是:
s1 is the same instance with s2
这证明我们只创建了一个实例.
二. 以静态变量为标志实现 Singleton在类中嵌入一个静态变量做为标志,每次都在进入构造器的时候进行检查.
问题在于构造器没有返回类型,如果确定创建一个实例成功与否.一个方法是调用一个函数来检查创建是否成功,然后简单的返回一个来自静态变量的值,但是这样做是不优雅的,而且容易发生错误.比较好的做法是创建一个当创建了一个以上的实例时可以抛出异常的类,这个类仅仅是调用父类方法,好处是用了自己命名的异常类型,错误信息更加清晰:
class SingletonException extends RuntimeException { public SingletonException(String s) { super(s); }}class Singleton { static boolean instance_flag = false; // true if 1 instance public Singleton() { if (instance_flag) throw new SingletonException("Only one instance allowed"); else instance_flag = true; // set flag for 1 instance }}// 测试类public class singletonTest { static public void main(String argv[]) { Singleton s1, s2; // create one incetance--this should always work System.out.println("Creating one instance"); try { s1 = new Singleton(); } catch (SingletonException e) { System.out.println(e.getMessage()); } // try to create another spooler --should fail System.out.println("Creating two instance"); try { s2 = new Singleton(); } catch (SingletonException e) { System.out.println(e.getMessage()); } }}
?
singletonTest运行结果是:
Creating one instance
Creating two instance
Only one instance allowed
可以看出,第一个实例顺利创建,第二个实例创建实抛出了我们自定义的异常.
三. 用注册器机制来创建 Singleton首先用集合中的Hashtable 和Enumeration来实现addItem(Object key,Object value),getItem(Object key), ,removeItem(Objectkey)等方法实现一个管理器,将key和value一一关联起来,客户程序员创建实例前首先用addItem方法进行注册,再用getItem方法获取实例.Hashtable中的key是唯一的,从而保证创建的实例是唯一的,具体实现限于篇幅不再细说,在Prototype模型的应用一文中我将会给出一个实现注册器的代码.用注册器机制来创建Singleton模式的好处是易于管理,可以同时控制多个不同类型的Singleton实例.
回页首
小结
?
- Singleton模式可以方便的进行扩充,产生指定数目的实例.在The Design Patterns Java Companion一书中曾提到过用静态类的方式来实现Singleton模式,并指出java.lang.Math就是一个例子,这里我并不表示赞同,因为Math并不是一个真正的对象,我们只是直接调用Math类所包装的静态方法而已,根本就没有创建实例的过程,又从何说起只产生一个实例呢?这个问题我曾到Javaranch的论坛上发过帖子,所有回帖的人也都是对这一观点持否定态度.在多线程的程序中,singleton可能会变的不可靠,可能会出现多个实例,解决的办法很简单,加个同步修饰符:public static synchronized Singleton getInstance().这样就保证了线程的安全性.最后要说的是大家可能会看见一些其他实现Singleton模式的方法,因为模式在具体的应用时是灵活的,不是一成不变的,并没有一个固定的做法,但大都是上面几种方法的变形.