在EffectiveJava Item3 中,对于单例(Singleton),做出了一个解释:单例就是一个只能实例化(instantiate) 一次,且恰好一次的类。
单例模式的缺点,在于难以测试其客户端(client),对于singleton类不能采用一个mock的实现,除非单例类实现了一个接口(interface)。
一、JDK 1.5之前的单例实现方法
JDK 1.5 release之前,一般有两种方法,都是采用保持constructor私有和公开一个static memeber来提供solo instance 访问。
第一种方法:public static final member方法
第二种方法:static factory:
这两种方法比较起来,public field 方法的优势在于Singleton的声明清晰明了:它提供了一个public static final的属性,因此总是包含同一个对象的引用。缺点在于,没有任何performance的优势。当代JVM,对于static factory method的调用(call),会采用内联(inline)的方式
另外,static factory method的另外一个优势,就是后期可以灵活改变是否是单例类,而不用修改已经暴露的API。
当面临serialiable时,仅仅考加上一个Serialiable接口是不合适的, 因为readObject()方法总是返回一个新的实例对象,就像java中的构造器一样。你可以使用readResolve()方法来避免这种情况, 需要将每一个field都添加一个关键字:transient,并提供一个readResolve方法, 通过像下面的例子中这样用单例来替换新创建的实例:
二、JDK 1.5 之后的enum 实现Singleton
在JDK1.5之后,可以通过enum来实现单例:
单例模式的缺点,在于难以测试其客户端(client),对于singleton类不能采用一个mock的实现,除非单例类实现了一个接口(interface)。
一、JDK 1.5之前的单例实现方法
JDK 1.5 release之前,一般有两种方法,都是采用保持constructor私有和公开一个static memeber来提供solo instance 访问。
第一种方法:public static final member方法
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
//Singleton with public final field
public
class
Elvis{
public
static
final
Elvis INSTANCE=
new
Elvis();
private
Elvis(){
//...}
public
void
leaveTheBuilding(){...}
}
|
第二种方法:static factory:
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
9
|
public
class
Elvis{
private
static
final
Elvis INSTANCE=
new
Elvis();
private
Elvis(){...}
public
static
Elvis getInstance(){
return
INSTANCE}
public
void
leaveTheBuilding(){...}
}
|
这两种方法比较起来,public field 方法的优势在于Singleton的声明清晰明了:它提供了一个public static final的属性,因此总是包含同一个对象的引用。缺点在于,没有任何performance的优势。当代JVM,对于static factory method的调用(call),会采用内联(inline)的方式
另外,static factory method的另外一个优势,就是后期可以灵活改变是否是单例类,而不用修改已经暴露的API。
当面临serialiable时,仅仅考加上一个Serialiable接口是不合适的, 因为readObject()方法总是返回一个新的实例对象,就像java中的构造器一样。你可以使用readResolve()方法来避免这种情况, 需要将每一个field都添加一个关键字:transient,并提供一个readResolve方法, 通过像下面的例子中这样用单例来替换新创建的实例:
[Java]
纯文本查看
复制代码
1
2
3
4
|
//readResolve to prevent another instance of Singleton
private
Object readResolve(){
return
INSTANCE;
}
|
二、JDK 1.5 之后的enum 实现Singleton
在JDK1.5之后,可以通过enum来实现单例:
[Java]
纯文本查看
复制代码
1
2
3
4
5
|
//Enum singleton -the preferred approach
public
enum
Elvis{
INSTANCE;
public
void
leaveTheBuilding(){...}
}
|