我有一個使用Spring IoC容器的Java EE項目。何時應該使用依賴注入和實用程序方法?
我剛剛在Utils
類的靜態方法sendMail(long list of params)
中找到。我不知道爲什麼,但是我覺得如果我們有單獨的類(Spring bean和單例作用域)將負責發送電子郵件,它會更好看。但我找不到任何證明我的立場的論據。
那麼,在這個(相當普遍)的情況下使用DI有什麼優點(或缺點)嗎?
我有一個使用Spring IoC容器的Java EE項目。何時應該使用依賴注入和實用程序方法?
我剛剛在Utils
類的靜態方法sendMail(long list of params)
中找到。我不知道爲什麼,但是我覺得如果我們有單獨的類(Spring bean和單例作用域)將負責發送電子郵件,它會更好看。但我找不到任何證明我的立場的論據。
那麼,在這個(相當普遍)的情況下使用DI有什麼優點(或缺點)嗎?
通常爲靜態函數的混合類型的類通常不是好東西。我曾在一個項目中看到過那種叫UglyGlobals的類。至少他們是誠實的!一般來說,你是對的。像郵件是一個很好的候選人變成被注入的單身bean。
如果需要發送電子郵件使用MailSender
接口(樣品名稱)的類,而不是一個static Utils.sendMail(...)
方法,那麼你可以很容易地進行單元測試這些類在單元測試中模擬/不同的實施MailSender
交換,而不是使用真正的實現。
這可以讓你測試時,郵件發送成功,這些類的行爲,當異常/錯誤捕獲等
如果類使用像你描述了一個靜態方法,那麼你不能實際單獨測試這些類的行爲,而不實際發送電子郵件 - 在這一點上,它不是一個有效的,孤立的單元測試,因爲您現在將依賴於1)郵件發送代碼2)發送郵件服務器等。
+1。這不是我的情況(在項目中沒有單元測試),但一般來說,你的論點是絕對正確的。 – Roman 2010-05-03 15:03:55
*項目中沒有單元測試*,那應該是紅旗。像這樣的靜態方法的使用和DI的缺乏可能使單元測試幾乎不可能。 – 2010-05-03 15:14:20
是的!我會根據我自己最近的經驗給你舉個例子。
我們最近將一堆應用程序從發送電子郵件直接切換到使用數據庫隊列發送消息。消息在DB中排隊,然後通過批處理進程發送。這使我們能夠處理SMTP服務器停機,重新發送消息,控制可從我們的開發服務器發送什麼消息,驗證消息是否實際發送等。
發送電子郵件這樣簡單的事情當然可以你可能想在未來改變。注入一個實現會使它更容易做到這一點。
+1。我認爲它在我的項目中有時可能會發生變化。 – Roman 2010-05-03 15:06:29
春郵件
首先,我想奉勸你看看在org.springframework.mail package。它提供了一個有用的實用程序庫來發送電子郵件,並作爲抽象來隱藏底層郵件系統的具體情況。
而且由於您已經在使用spring,因此只要它提供了您的應用程序所需的關於發送郵件的所有內容,就意味着使用此庫並不痛苦。
靜態方法與依賴注入
使用依賴注入給你的可能性,輕鬆地切換到其他實現。靜態方法調用將消費者的實現緊密地綁定到消費者正在使用的服務上。
測試消費者意味着您將集成測試消費者與服務,而不是單獨測試您的消費者。這使得你總是依賴這些靜態方法的基礎邏輯,並且由於這些靜態方法之一的錯誤而使得測試可能失敗。
DI可以輕鬆地模擬您的編寫測試的實現。例如,假設您要測試密碼重設流程。使用硬編碼的Utils.sendMail(),您的測試代碼將被迫製作一個模擬SMTP服務器,閱讀並解析電子郵件,然後單擊密碼重置鏈接。如果你使用過DI,你可以通過模擬Emailer
對象。這樣,您可以編寫超快速的單元測試,而不必擔心外部集成問題。
您也可以輕鬆地交換實現。例如,Google App Engine有一個自定義的sendMail API - 因此您很難同時支持GAE版本的代碼和非GAE版本。 (爲了爭論,只是假設遷移到GAE很容易,而不是顯然)。
最後,你的代碼更模塊化。一個特殊的類(ResetPassword)可能僅僅依賴於Util.sendMail(),但是Util可能是一個廚房水槽,其方法可以在陽光下做所有事情。因此,如果您想在另一個項目中重新使用ResetPassword,則必須複製整個Utils類以及Utils需要工作的多個相關jar。它不是一個好的選擇。
測試用例角度已經在其他響應中被覆蓋(我應該輸入更快:),但代碼模塊性參數仍然適用 – 2010-05-03 15:06:24
您希望避免依賴於狀態的靜態實用程序方法,或者您在某些情況下(通常是測試)出於某種原因可能想要避免的外部影響。
在這種情況下,發送郵件可能取決於外部狀態(郵件服務器的可用性),併產生您可能希望避免的(發送電子郵件)的外部影響。對於開發和測試,您可能通常不希望發送電子郵件。在其他情況下,您可能想測試一封電子郵件已發送,但如果郵件實際上正在發送,您如何執行此操作?設置一些複雜的系統來檢查電子郵件的實際電子郵件收件箱?
如果你注入代表MailSender
的接口,你可以提供一個NoopMailSender
,什麼也不做,當你不關心所發送的電子郵件和僞造的StubMailSender
收集電子郵件的List<EmailMessage>
,當你想要的是通過它發送能夠測試某些電子郵件是由您的代碼發出的。
UglyGlobals?尼斯。 – 2010-05-03 15:00:09