如果你序列化一個單例類,然後兩次重構它,那麼你就會得到那個單例類的兩個執行個體,除非你實現readResolve()方法,像下面這樣:
例1 一個可序列化的單例類
Java代碼
import
org.apache.log4j.Logger;
public class Singleton implements java.io.Serializable
{
public static Singleton
INSTANCE = new
Singleton();
protected Singleton()
{
// Exists only to thwart
instantiation.
}
private Object readResolve()
{
return
INSTANCE;
}
}
上面的單例類實現從readResolve()方法中返回一個唯一的執行個體;這樣無論Singleton類何時被重構,它都只會返回那個相同的單例類執行個體。
例2測試了例1 的單例類
例2 測試一個可序列化的單例類
Java代碼
import
java.io.*;
import
org.apache.log4j.Logger;
import
junit.framework.Assert;
import
junit.framework.TestCase;
public class SingletonTest extends TestCase
{
private Singleton sone = null,
stwo =
null;
private static Logger logger =
Logger.getRootLogger();
public SingletonTest(String
name) {
super(name);
}
public void setUp()
{
sone =
Singleton.INSTANCE;
stwo =
Singleton.INSTANCE;
}
public void
testSerialize()
{
logger.info("testing singleton
serialization...");
writeSingleton();
Singleton s1 =
readSingleton();
Singleton s2 =
readSingleton();
Assert.assertEquals(true, s1 ==
s2);[/b]
}
private void
writeSingleton()
{
try {
FileOutputStream fos = new
FileOutputStream("serializedSingleton");
ObjectOutputStream oos = new
ObjectOutputStream(fos);
Singleton s =
Singleton.INSTANCE;
oos.writeObject(Singleton.INSTANCE);
oos.flush();
}catch(NotSerializableException se)
{
logger.fatal("Not Serializable Exception: " +
se.getMessage());
}catch(IOException iox)
{
logger.fatal("IO Exception: " +
iox.getMessage());
}
}
private Singleton
readSingleton()
{
Singleton s =
null;
try {
FileInputStream fis = new
FileInputStream("serializedSingleton");
ObjectInputStream ois = new
ObjectInputStream(fis);
s =
(Singleton)ois.readObject();
}catch(ClassNotFoundException cnf)
{
logger.fatal("Class Not Found Exception: " +
cnf.getMessage());
}catch(NotSerializableException se)
{
logger.fatal("Not Serializable Exception: " +
se.getMessage());
}catch(IOException iox)
{
logger.fatal("IO Exception: " +
iox.getMessage());
}
return
s;
}
public void
testUnique()
{
logger.info("testing singleton
uniqueness...");
Singleton another = new
Singleton();
logger.info("checking singletons for
equality");
Assert.assertEquals(true, sone ==
stwo);
}
}
前面這個測試案例序列化例1
中的單例類,並且兩次重構它。然後這個測試案例檢查看是否被重構的單例類執行個體是同一個對象。下面是測試案例的輸出:
Java代碼
Buildfile:
build.xml
init:
[echo] Build 20030422 (22-04-2003
11:32)
compile:
run-test-text:
[java] .INFO main: testing singleton
serialization...
[java] .INFO main: testing singleton
uniqueness...
[java] INFO main: checking singletons for
equality
[java] Time:
0.1
[java] OK (2
tests)
單例模式結束語
單例模式簡單卻容易讓人迷惑,特別是對於Java的開發人員來說。在這篇文章中,作者示範了Java開發人員在顧及多線程、類載入器和序列化情況如何?單例模式。作者也展示了你怎樣才能實現一個單例類的註冊表,以便能夠在運行期指定單例類。