有些时候,允许自由创建某个类的实例没有意义,还可能造成系统性能下降(因为创建对象所带来的系统开销问题)。例如整个系统中只有一个窗口管理器,只有一个假脱机打印设备;在JavaEE应用中可能只需要一个数据库引擎访问点,Hibernate访问时只需要一个SessionFactory实例,如果在系统中为它们创建多个实例就没有太大的意义。
如果一个类始终只能创建一个实例,则这个类被成为单例类,这种模式就被称为单例模式。
对于Spring框架而言,可以在配置Bean实例时指定scope="singleton"来配置单例模式。不仅如此,如果配置<bean../>元素时如果没有指定scope属性,则该实例默认就是单例的行为方式。
Spring推荐将所有的业务组件,DAO组件,数据源等配置成单例的行为方式,因为这些组件无需保存任何用户状态,故所有客户端都可以共享这些业务逻辑组件、DAO组件等。如果不借助Spring框架,我们也可以手动实现单例模式。为了保证该类只能产生一个实例,程序不能允许自由创建该类的对象,因此我们需要使用private来修饰该类的构造器,从而将其隐藏起来。
将构造器隐藏起来后,需要提供一个public方法来作为访问该类的访问点,用于创建该类的对象,且该方法必须使用static修饰(因为在调用方法前还不存在对象,因此调用该方法的不可能是对象,只能是类)。
除此之外,该类还必须缓存已经创建的对象,否则该类无法知道是否曾经创建过实例,也就无法保证只创建了一个实例。为此该类需要使用一个静态属性来保存曾经创建的实例,且该属性需要被静态方法访问,所以属性也应该使用static修饰。
下面是一个单例类的实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
Singleton {
//使用这个对象来缓存已经创建的实例
private
static
Singleton singleton;
//构造函数是private的,因此只能在本类中访问
private
Singleton(){}
//这个public方法来获取这个创建的实例
public
static
Singleton getInstance() {
if
(instance ==
null
) {
singleton =
new
Singleton();
}
return
singleton;
}
}
|
下面是测试类:
1
2
3
4
5
6
7
|
public
class
Test {
public
static
void
main(String args[]) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1==s2);
//将输出true
}
}
|
在上面的Test类的代码中,只有通过Singleton的getInstance方法才可以获得Singleton的实例。在第一次调用时会在Singleton类中创建一个示例,第二次调用则返回这个已经创建的实例,以后每次调用也是。这就保证了Singleton实例只创建了一次。由于每次调用都返回的是同一个实例,因此,在Test中将输出true。
综上,一般的单例模式的类都具有以下特点:
-
私有构造器
-
私有静态类成员变量
-
公有获取该变量的方法