GoF著作中未提到的設計模式(3):Null Object

Null Object模式的目的包括:

1. 當對象提供者無法提供指定類型的對象時, 返回一個什麼都不做的對象, 這對調用者是透明的,並且調用者不用判斷獲得的對象是否爲null了,當然,對象提供者必須告知調用者(通過約定等).

2. 有時候需要傳遞一個什麼都不做的某個類型的對象給合作方. 例如某個函數需要實現特定接口的對象(通過參數傳入)進行某些操作, 該函數的調用者在某些情況下希望不進行這些操作,那麼他就可以傳進來一個實現了該接口但函數體全爲空的對象,這個對象就是Null Object.


  舉個例子,從某處(不是通過new來創建)獲得一個對象後,我們的第一反應就是判斷這個對象是否爲null,這都成爲程序員的本能了。

如果爲null,則做一些特殊處理,就像下面的代碼片段:

複製代碼
EventRecorder recorder = EventRecorderFactory.getRecorderByType(0);
if( recorder ==null ){
Log.error(
"Recorder對象爲空");
lastErrorCode 
=0;
}
else{
recorder.record(
"記錄點啥...");
}
複製代碼

看到了沒有,爲了處理這個對象爲null的情況,增加了很多行代碼,而且類似的代碼片段充斥在整個項目中,看着都想吐了。  

要是EventRecorder的作者拍着胸脯向你保證:我給你的EventRecorder對象絕對不會是null!不然我生孩子沒.......

人家都這麼說了,那咱就應該相信他!

以後寫代碼就舒心多了,看着也清爽:

EventRecorder recorder = EventRecorderFactory.getRecorderByType(0);
recorder.record(
"終於不用判斷是否爲NULL了.......");

Null Object模式就可以實現上面的約定。

下面是EventRecorder的聲明:
 

publicinterface EventRecorder{
publicvoid record(String event);
}


增加兩個實現類:
 

複製代碼
publicclass RecordEventToDatabase implements EventRecorder{
publicvoid record(String event);
// 記錄內容到數據庫中
}
}

publicclass RecordEventToFile implements EventRecorder{
publicvoid record(String event);
// 記錄內容到文件中
}
}
複製代碼


下面是EventRecorderFactory中getRecorderByType的簡單實現:
 

複製代碼
publicstatic EventRecorder getRecorderByType(int type){
EventRecorder recorder 
=null;
if(type ==0)
recorder 
=new RecordEventToDatabase();
elseif(type ==1)
recorder 
=new RecordEventToFile();
return recorder;
}
複製代碼


可以看出這個方法的返回值可能是null,調用者就需要判斷這種情況。

下面我們實現一個什麼都不做的EventRecorder:

publicclass NullEventRecorder implements EventRecorder{
publicvoid record(String event);
}


下面是修改後的getRecorderByType:
 

複製代碼
publicstatic EventRecorder getRecorderByType(int type){
EventRecorder recorder 
=null;
if(type ==0)
recorder 
=new RecordEventToDatabase();
elseif(type ==1)
recorder 
=new RecordEventToFile();
else
recorder 
=new NullEventRecorder(); // 這就是Null Object
return recorder;
}
複製代碼

這樣就可以保證該方法的返回值永遠不會爲null了。

 再舉一個例子來說明第二個目的:

複製代碼
// 付款人接口

publicinterface Payer {

publicvoid pay(int money);

}

// 使用信用卡付款

public PayerByCard implements Payer{

publicvoid pay(int money){

// 刷卡

}

}

// 不付款(這就是一個Null Object, 什麼都不做)

public NullPayer implements Payer{

publicvoid pay(int money){

}

}
複製代碼

 

下面是一個使用Payer對象的方法:

複製代碼
publicvoid pay(Payer payer){

if(payer==null)

throw Exception;

payer.pay();

}
複製代碼

 

下面是一個使用場景:

複製代碼
Payer payer =null;

if(userType =="黑社會老大")

payer 
=new NullPayer();

else

payer 
=new PayerByCard();

payer.pay();

// 享受服務....
發佈了27 篇原創文章 · 獲贊 20 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章