在 C# 開發中,我們經常遇到這樣的場景:從集合或管理類中根據鍵值獲取物件。若鍵值不存在,方法回傳 null。調用者若不檢查 null 直接使用,極易拋出 NullReferenceException。為了避免這一問題,調用者往往被迫編寫大量重複的防禦性代碼:
Student student = studentCollection.GetStudentByID("13432");
if (student == null) {
// 處理 null,拋出異常或記錄日誌
throw new ArgumentException("學生不存在");
}
// 後續業務邏輯...
這不僅導致代碼冗餘,還違反了「單一職責原則」——調用者不應負責驗證方法契約的有效性。Safely 方法模式應運而生,它通過契約擴展,保證返回非 null 的有效物件,或拋出明確異常,將錯誤處理集中化,簡化調用端邏輯。
根據「契約式設計」思想,方法定義是調用者與實現者之間的契約。原方法 GetStudentByID 的後置條件允許返回 null。Safely 方法不修改原方法,而是提供一個擴展契約的新方法(慣例命名為 GetStudentByIDSafely),其契約承諾:
NotExistedStudentException),而非返回 null。此處「適用」一詞關鍵:null 本身非無效,只是不適應「調用者假定物件必須存在」的場景。
命名慣例:在原方法名後綴 Safely(如 GetXXXSafely)。實現極簡——委託原方法,檢查結果,拋出異常或返回物件:
public Student GetStudentByIDSafely(string sid)
{
Student student = GetStudentByID(sid);
if (student == null)
{
throw new NotExistedStudentException(sid); // 自定義異常攜帶上下文信息
}
return student;
}
調用端代碼變得乾淨:
// 無需檢查 null,異常由全域處理機制或上層捕獲
Student student = studentManager.GetStudentByIDSafely("13432");
student.EnrollCourse(courseId); // 直接使用
null 檢查與異常拋出代碼。NotExistedStudentException),優於通用的 ArgumentNullException 或 NullReferenceException。.NET 2.0 引入 Nullable<T>(即 T?)解決值類型可為 null 問題,而 Nullable Object 模式則為引用類型提供「空物件」實例,統一調用方式(如 ToString() 不拋異常)。兩者差異在於:
語言無關性:Safely 模式純屬設計層面,適用於 Java、C++ 等任何支援異常與介面的語言。
Safely 方法是一個輕量級、高收益的慣用模式。它不引入新類型、不改變現有契約,僅通過一個薄封裝層,將「驗證有效性」的責任從調用者轉移到提供者,實現代碼的簡化與語義的明確化。在領域驅動設計中,它更是體現「設計契約」精神的實用技巧。