2

我有以下類,後面的服務類耦合到一個特定的容器,但如果我使用前爲什麼控制器類應該注入服務類依賴關係,而不是僅使用服務類,並將其留給服務類解決依賴關係?控制器注入服務類依賴關係或將其留給服務來解決它自己的依賴關係?什麼是首選的方式

public class ProfileController { 

    public ProfileController(IProfileService profileService, IProfileRepository profileRepository, IUnitOfWork unitOfWork, IDatabaseFactory databaseFactory) { 
    profileService.Get(); 
    } 
} 

public class ProfileService:IProfileService { 

    public ProfileService(IProfileRepository profileRepository, IUnitOfWork unitOfWork, IDatabaseFactory databaseFactory) { 
    profileService.Get(); 
    } 
} 

public class ProfileController { 
    public ProfileController(IProfileService profileService) { 
          profileService.Get(); 
    } 
} 

public class ProfileService:IProfileService { 

    public ProfileService() { 
     var dbfactory=container.Resolve<IDatabaseFactory>(); 
     var unitofwork=container.Resolve<IUnitofWork>(); 
     var rep=container.Resolve<IProfileRepository>(); 
     rep.Get(); 
    } 
} 

回答

1

服務類不應該解決它的依賴。所以你應該選擇1.實例應該完全不可知的DI容器。

爲什麼?

問題的分離:依賴注入的主要思想是將對象的實例化考慮爲獨特的關注點,這是在一個地方照顧的:容器。容器的工作是創建實例並在它們之間設置引用。當你讓實例本身使用容器時,你會破壞這個概念。

您模塊類的可重用性:當您有一個'使用'DI容器的類時,不能在不同的體系結構中使用此類,包括不同的DI框架,而無需更改它。雖然你可能不想,但你沒有充分的理由限制自己。

語義清晰度:您的構造函數參數應回答以下問題:我需要創建該類的實例。在你的情況,這是東西:IDatabaseFactory等,而不是沒有(())。

可測試性:你不希望你的課程要求整個DI基礎設施工作。也許爲了測試模擬應該做的原因,在運行時由你的DI容器完成。這與「可重用性」有關。

快速失敗:假定依賴關係不可解析:建立容器時拋出異常並非在實例化類時非常好。

摘要

container.Resolve(...) 

不應該發生在你的模塊。

+0

感謝@Marc我同意,我喜歡你的語義清晰的點。我贊成選項1 – sbtech100 2013-03-13 15:10:40

+0

歡迎您!我也去過那裏,把選項從1改爲2,然後再改回來;) – Marc 2013-03-13 15:13:59

0

我覺得這兩個例子都偏離了軌道。

建議的解決方案:

public class ProfileService:IProfileService { 

    public ProfileService(IProfileRepository profileRepository, IUnitOfWork unitOfWork, IDatabaseFactory databaseFactory) { 

    } 
} 

用以下方式在調用以下使用該服務。

public class ProfileController { 
    [ConstructorInjection] 
    public ProfileController(IProfileService profileService) { 

    } 
} 

或者

public class ProfileController { 
    public ProfileController(IProfileService profileService) { 

    } 
} 

public class ProfileController { 

    public ProfileController() { 
     this.service = resolveFromContainer.Get<IProfileService>(); 
    } 
} 

public class ProfileController { 

    public ProfileController() { 
     this.service = new ServiceFactory.get<IProfileService>() 
    } 
} 

(1)。在上述兩種情況下,在這兩種情況下,我都沒有看到問題分離問題。控制器沒有執行存儲庫作業。它僅提供使用的資源庫。

只要曝光模塊去。對於共享組件我同意100%我們不應該強制呼叫者使用di容器。

但是,我們可以構建共享代碼並讓消費應用程序選擇如何注入共享模塊依賴項。 (2).Marc在他的回答中提到了這一點:「語義清晰度:你的構造函數參數應該回答以下問題:我需要什麼來創建該類的實例,你的情況是這樣的:IDatabaseFactory等等而不是什麼(())「。

我同意100%,但是如果你看到控制器的構造函數。它不僅有服務,而且還有很多其他的東西。我需要其他所有東西來控制我的控制器嗎? 這是一個應用程序特定的問題和答案不能通用化。 如果您只需要該服務工作,然後通過該服務。不要傳遞服務依賴關係,因爲它沒有定義控制器。它定義了服務。

傳遞存儲庫不同於將開發人員密鑰傳遞給庫。儘管您可以靈活地提供存儲庫,但您也正在指定目的地。這在某些情況下很有用..想想存儲日誌信息的庫(我們指定了存儲位置),這些代碼在抽象出代碼的RequestProcessor模式中也很有用。

問:如果您希望您的服務保存並返回,那麼將存儲庫dbFactory傳遞給它是否正確?

在上面的新解決方案。 配置文件服務代碼不會更改。配置文件服務可能需要DB,Repository 但是控制器是否需要存儲庫,工廠,服務的所有工作?這是一個特定的應用程序

* 問:是否需要傳遞參數來創建控制器,還是其中一些被間接用於創建其他依賴關係? *

(3)「container.Resolve(...) 不應發生在您的模塊中。」

* 問:你指的是什麼模塊?你是說我們應該使用DI容器,但不知何故決不會在任何一段代碼中使用DI屬性/解析方法/依賴配置?*

(我可以看到DI容器的作者畏縮在這種思想)

問:你能不能回答,這是哪裏好使用的方法解決?

我同意100%共享代碼不應該使用解析方法。然而,控制器可以像特定於應用程序的代碼一樣,並且確實需要容器來注入/組裝其依賴項。

DI容器是一個核心框架,是您的應用程序設計的第一級公民。如果我們沒有選擇一個DI容器來構建,我們是否真的擁抱DI?

如果DI容器是像.NET庫這樣的頭等公民,那麼如果沒有額外的工作,就不會「計劃」更改容器。拍攝代碼很容易讓你切換DI容器的工作量太大,最好留給微軟/社區來解決。

摘要: 我的答案與大多數的Marc的想法同意*然而無論是提出的解決方案的答案犯規回答他正確地提出的所有問題。 *

參考文獻:

  1. http://martinfowler.com/articles/injection.html
  2. http://msdn.microsoft.com/en-us/magazine/dd882510.aspx

輕微的抱怨: 以上兩種解決方案上採用工作/程序存儲庫

引用代碼的單位的小評從上面的鏈接。 public void RunCommands(Invoice invoice){ IUnitOfWork unitOfWork = _unitOfWorkFactory.StartNew();

UnitOfWorkfactory應該管理數據庫工廠,不應將其傳遞給服務。

恕我直言

我們正在做的,這並不覺得我的權利依賴同樣手把手的指導。這同樣適用於倉庫工廠。

工廠應該設置上下文,如db上下文等責任不應該在服務中。

這可能是更好的界面 公共ProfileService(IProfileRepository profileRepository,IUnitOfWork的UnitOfWork)