singleton即单例模式。【第1条】中我提到的Session性质的全局唯一实例既是单例模式。它只能被实例化一次,通常代表本质上具有唯一性质的东西。
除了Session的例子外,我这里还有一个很微妙的例子:
new MessageBox("Hello World ! ").show();
MessageBox.show(new MessageBox("Hello World ! ");
MessageBox.show("Hello World ! ");
MessageBox.getInstance().show("Hello World ! ");
很显然第一个是多实例模式,每次new的时候都会构造一个新的MessageBox类(如果MessageBox是非可变类,可能并非每次都会构造新的,如果碰巧形参的字符串曾经出现过,就不必再构造新的实例了)。
第二个使用一个静态方法(只是普通的静态方法)来显示消息框,但是作为传入的参数,还是一个刚刚被创建的MessageBox类。
第三个和第二个比较类似,只是少了一层“脱了裤子放屁”的new,直接把String作为参数给show()。现在是单例模式了吗?答案是可能是。也可能不是,而“进一步”是不可实例化的工具类(util),参考【第3条】。
第四个呢,从getInstance一眼就能看出,这不是【第1条】中刚刚讲到的静态工厂方法吗。OK,只要MessageBox的作者不是个糊涂的程序员,那么可以几乎可定它是一个单例模式。
那么如何才能保证一个类只能被实例化一次呢?(也就是说怎么才能说刚才那个MessageBox的作者不是个糊涂的程序员呢?)实现的方法有2种:这2种的共性是
1)都把构造函数声明为私有的,别人无法通过调用构造函数来创建类的事例了。
2)都有一个静态的成员,用来保持(保存)这个“单实例”
不同点是:
方法1)将这个静态成员声明为公有的,供他人直接使用。
public class Example{ public static final Example INSTANCE=new Example(); private Example(){ //构造函数为私有 ...} .... }
方法2)将这个静态成员声明为私有的,通过静态工厂方法供他人使用。
public class Example{ private static final Example INSTANCE=new Example();//改为私有 private Example(){ //构造函数为私有 ...} public static Example getInstance(){ return INSTANCE; } .... }
2种方法的优缺点其实并不大,由于第2种更为灵活,对将来的扩展也留有更多的余地,所以我个人还是更倾向于第2种。
我在开发的Framework中,单实例的应用并不多(一个项目中如果太多反而是要思考了),其中一个最突出的应用就是UserSession,它记录了客户的登录信息,显然一个用户只能有一个UserSession。
通常这样的类最好也是非可变的,见【第13条】。但是由于其他原因这里的UserSession无法做成非可变类,这个到【第13条】时再细说。
【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208