所谓设计模式(Design Pattern),是为了满足对优秀、简单而且可重用的解决方案的需要。这就像我们在盖楼的时候,我们不会每次都从零开始来画图纸,而是参照某种已有的模式,然后在此基础上来设计它。而在面向对象程序设计中,“模式”是为了实现重用面向对象代码的一种方便做法。
根据“设计模式”的经典著作《Design Patterns:Elements of reusable Object-Oriented software》中所述,设计模式一般包含四个基本要素:
1.模式名称(pattern name):一个助记名,用几个词汇来描述模式的问题、解决方案以及效果。
2.问题(problem):描述了应该在何时使用模式。
3.解决问题的方案(solution):描述了设计的组成部分,它们之间的相互关系及各自的职责和协作方式。
4.效果(consequences):描述了模式应用的效果及使用模式应权衡的问题。
我们现在来考虑单子(Singleton)设计模式的需求背景。
在实际应用中,我们可能需要限制生成的对象个数只能为1个。比如,在开发图形应用的时候,在菜单栏上按下“帮助”菜单,将弹出一个帮助对话框,也就是生成了一个帮助对话框的实例,如果对话框已经出现,则即使再在菜单栏上按下“帮助”菜单,应用程序也不应该再生成新的对话框实例。这个时候,如果还是通过原来的用构造器来生成实例的方式,很难对其生成的实例个数进行控制。通过所谓的“单子设计模式”,可以实现这个功能。
单子设计模式的基本思路是在类的内部定义一个静态变量,当创建第一个实例时设置该变量。应用程序直接使用这个静态变量指向的实例就可以了。为了防止应用程序调用构造器来新建实例,必须限制构造器的访问,也就是将它的访问控制设置为“private”。
概括起来,要实现“单子设计模式”,可以利用下面的方式来完成:
创建一个类,满足:
构造器私有;
用一个私有、静态变量引用实例;
提供一个公有、静态方法获得实例。
下面来看一个这个实现的例子:
public class SingletonPattern {
private double r;
// 定义一个私有、静态的引用变量
private static SingletonPattern sp;
// 构造器私有
private SingletonPattern() {
r = java.lang.Math.random();
}
// 提供一个公有、静态方法获得唯一实例
public static SingletonPattern getInstance() {
if (sp == null)// 如果还未创建实例
{
sp = new SingletonPattern();// 则创建一个实例
}
return sp;// 将它返回
}
public double getR() {
return r;
}
public static void main(String args[]) {
SingletonPattern sp1 = SingletonPattern.getInstance();
SingletonPattern sp2 = SingletonPattern.getInstance();
System.out.println(sp1.getR());
System.out.println(sp2.getR());
}
}
在这个例子中,我们利用上面所讨论的方法实现了“单子设计模式”,为了简单的测试我们每次得到的对象是否为同一个对象,我们在构造器中给该类的实例变量r赋了一个随机的值。如果每次得到的实例是同一个,那么,它的实例变量r的值也必定相同。
为了测试这个类,在这个类中定义了一个main()方法,然后通过SingletonPattern类的静态方法getInstance()来获得两个SingletonPattern实例,分别赋给两个引用变量sp1和sp2,然后通过这两个实例的getR()方法将它的实例变量打印出来。运行上面的程序,可以得到类似如下的输出:
0.04960654267464748
0.04960654267464748
这说明,这两个引用变量指向的是同一个实例,也就是只有一个实例存在。因为这个类的构造器被定义为“private”,所以不能直接调用它的构造器来生成新的实例,这也就避免了通过直接调用构造器生成多个实例的情况。