這天小明問說
他接手維護的專案中, 從頭到尾都一律用 DI 屬性注入, 這是很好的設計方式嗎?
首先我先簡單說明一下, DI 的核心概念是寬鬆耦合, DI 有三種注入的方式:
public class MyHome {
IMailService _mailService;
public MyHome(IMailService mailService) {
_mailService = mailService;
}
}
以上程式碼示範了建構式注入, 當你手動 "new 一個物件" 就必須把 IMailService 物件帶進來.
因此該物件在沒有這些依賴物件時無法被建立.
public class MyHome {
public MyHome() {
}
public IMailService MailService { get; set; }
}
以上程式碼示範屬性注入, 當你手動 "new 一個物件", 不必一開始就把 IMailService 物件帶進來.
這意味著你的物件可以在沒有提供這些依賴時正常地工作.
原則上這種方式, 對於不注入相依物件的情況, 物件本身必須做些防護措施, 以免物件執行的時候, 因相依物件參考為 null 而引發 NullReferenceException 異常.
public class MyHome {
public MyHome() {
}
public void Run(IMailService MailService) {
...
}
}
以上程式碼示範方法注入, 當你手動 "new 一個物件", 跟屬性注入一樣, 也不必一開始就把 IMailService 物件帶進來. 只有在用戶端呼叫 Run 方法時才需要傳入 IMailService 相依物件.
現在我們了解三種注入的方式跟特性, 回頭看小明的問題, 他接手的專案中 "一律都用屬性注入" ,
以下是小明接手專案中的程式碼片段
public class MyHome
{
public IMailService MailService { get; set; }
public Ixxx1 xxx1 { get; set; }
public Ixxx2 xxx2 { get; set; }
public IxxxN xxxN { get; set; }
public void Run() {
MailService.Call();
...
}
}
以上程式碼有幾個問題:
另外小明的專案交接人也有疑問說:
那我把所有屬性注入通通改成建構式注入, 但是依賴物件超級多, 我不想在建構式看到一堆參數, 所以我才要把這些一堆依賴物件通通改成屬性注入阿
遇到這種問題,
我們就應該思考 "當這個物件的建構式需要的參數數量很多的時候",
可能是一種 "程式碼壞味道" (Code Smell),
表明您的物件做太多事情, 可能沒有遵循單一職責原則.
請考慮將程式碼重構為許多相互消耗的較小物件.
每當需要注入相依物件時, 建議優先考慮 "建構式注入" ,
因為 "new 物件" 的時候, 就要一併傳入所有相依物件,
對呼叫端來說相當明確直覺, 馬上可以得知這個物件相依於哪些第三方物件.