Java代碼
privatestaticClass?getClass(String?classname)
throwsClassNotFoundException?{
ClassLoader?classLoader?=?Thread.currentThread().getContextClassLoader();
if(classLoader?==null)
classLoader?=?Singleton.class.getClassLoader();
return(classLoader.loadClass(classname));
}
}
private static Class getClass(String classname)
throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader == null)
classLoader = Singleton.class.getClassLoader();
return (classLoader.loadClass(classname));
}
}
這個方法會嘗試把當前的線程與那個類載入器相關聯;如果classloader為null,這個方法會使用與裝入單例類基類的那個類載入器。這個方法可以用Class.forName()代替。
序列化
如果你序列化一個單例類,然后兩次重構它,那么你就會得到那個單例類的兩個實例,除非你實現readResolve()方法,像下面這樣:
例12 一個可序列化的單例類
Java代碼
importorg.apache.log4j.Logger;
publicclassSingletonimplementsjava.io.Serializable?{
publicstaticSingleton?INSTANCE?=newSingleton();
protectedSingleton()?{
//?Exists?only?to?thwart?instantiation.
}
privateObject?readResolve()?{
returnINSTANCE;
}
}
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類何時被重構,它都只會返回那個相同的單例類實例。
例13測試了例12的單例類:
例13 測試一個可序列化的單例類
Java代碼
importjava.io.*;
importorg.apache.log4j.Logger;
importjunit.framework.Assert;
importjunit.framework.TestCase;
publicclassSingletonTestextendsTestCase?{
privateSingleton?sone?=null,?stwo?=null;
privatestaticLogger?logger?=?Logger.getRootLogger();
publicSingletonTest(String?name)?{
super(name);
}
publicvoidsetUp()?{
sone?=?Singleton.INSTANCE;
stwo?=?Singleton.INSTANCE;
}
publicvoidtestSerialize()?{
logger.info("testing?singleton?serialization...");
??????writeSingleton();
Singleton?s1?=?readSingleton();
Singleton?s2?=?readSingleton();
Assert.assertEquals(true,?s1?==?s2);???}
privatevoidwriteSingleton()?{
try{
FileOutputStream?fos?=newFileOutputStream("serializedSingleton");
ObjectOutputStream?oos?=newObjectOutputStream(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());
}
}
privateSingleton?readSingleton()?{
Singleton?s?=null;
try{
FileInputStream?fis?=newFileInputStream("serializedSingleton");
ObjectInputStream?ois?=newObjectInputStream(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());
}
returns;
}
publicvoidtestUnique()?{
logger.info("testing?singleton?uniqueness...");
Singleton?another?=newSingleton();
logger.info("checking?singletons?for?equality");
Assert.assertEquals(true,?sone?==?stwo);
}
}
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); }
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);
}
}
前面這個測試案例序列化例12中的單例類,并且兩次重構它。然后這個測試案例檢查看是否被重構的單例類實例是同一個對象。下面是測試案例的輸出:
Java代碼
Buildfile:?build.xml
init:
[echo]?Build20030422(22-04-200311:32)
compile:
run-test-text:
[java]?.INFO?main:?testing?singleton?serialization...
[java]?.INFO?main:?testing?singleton?uniqueness...
[java]?INFO?main:?checking?singletonsforequality
[java]?Time:0.1
[java]?OK?(2tests)
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開發者在顧及多線程、類載入器和序列化情況如何實現單例模式。作者也展示了你怎樣才能實現一個單例類的注冊表,以便能夠在運行期指定單例類。
posted on 2008-05-05 22:12 bcterry 閱讀(38) 評論(0) ?編輯 ?收藏