2016-08-05

[Design Pattern] [C#] Null Object Pattern

身為一名Developer
你一定寫過類似這樣的code

Employee em = getEmployeeByDB();            
if(em != null)  {   em.IsAvailable() }
if(em != null && em.IsAvailable()) { … }
......
if(em != null) { em.IsAvailable() } if(em != null) { em.IsAvailable() } if(em != null) { em.IsAvailable() } if(em != null) { em.IsAvailable() } ......

Employee em 是來自於 getEmployeeByDB()
我們要先確認它是不是null 接下來才呼叫它的method

所以我們每次getEmployeeByDB 之後都要判斷它是不是null

是不是很麻煩 ???
是不是很麻煩 ???
是不是很麻煩 ???

所以Null Object Pattern的存在就是為了解決這個困擾

讓我們看看原本正常的一個Case
這個故事是在描述
1. 根據ID去DB查詢 並回傳一個Employee的Instance
2. 如果查無此人 就回傳 null

來看看正常情況下 程式怎麼寫吧
em 是來自於 getEmployeeByDB(string id)
所以 em 有可能是 null
因此在使用em.IsAvailable()之前必須要先確認 em 不是 null


假設我們僅讓ID為"10001" 才當作是員工 其他人都查無此人而回傳 null


Employee裡面的實作 僅為範例


getEmployeeByDB() 原本預期會回傳兩種結果
一個是正常的Employee 另一個是null



讓我們看看 如果換成 Null Object Pattern的話 要怎麼做

一個簡單的原則 產生一個介面跟Employee一樣的Class 但是要實作當狀態是Null 或是 Failure時的回傳值 (也可能是什麼都不做)



實作步驟 :

1. 我們可以將Employee抽象出一個抽象類別 ANullableEmployee
讓Employee繼承ANullableEmployee






[註] 這裡的NullableEmployee其實就是Employee 我只是換個名字

2. 實作一個Private的Null Class, NullEmployee (同樣繼承ANullableEmployee) 這是要表示當狀態是Null的物件

    這裡值得注意的點是 要override每個抽象類別定義的方法 實作的內容必須考慮當狀態是Null時 這個method必須回傳什麼才合理

3. 在抽象類別 ANullableEmployee 中 產生一個NullEmployee的靜態變數 NULL



4. 當狀態是Null或是有誤時 回傳NullEmployee 而非null



5. Caller可以直接呼叫ANullableEmployee定義的方法 不用像之前一樣要一一檢查


如果真的還是必須要判斷是不是null
可以直接去比對
em == ANullableEmployee.NULL



Null Object Pattern 是一個簡單的實作
但是能避免每次都必須重複確認的動作
不過一個比較麻煩的點是
要去思考 要用什麼行為去代表NULL
另一方面 當抽象類別增加方法時 內部的NullEmployee也一定要複寫這個新方法喔