2016-09-28 46 views
0

我試圖使用IOC/DI容器,而是什麼時候來創建一個子窗口,什麼是最好的做法是什麼?IOC/DI容器和子窗口創建困境

當我有困難是:

public class ParentWindow : Form 
{ 
    public void OpenChildWindow() 
    { 
     var child = IocContainer.Instance.Resolve<ChildWindow>(); // big issue !!! an-ti server locator pattern 
     child.Show(); 
    } 
} 

或者

public class ParentWindow : Form 
    { 

      private Container _container 

      public ParentWindow(Container container) // no, no, you have dependence on container 
      { 
      } 

     public void OpenChildWindow() 
     { 
      var child = _container.Resolve<ChildWindow>(); 
      child.Show(); 
     } 
    } 

我的解決方案

public class ParentWindow : Form 
{ 
    private IFormFactory _factory 

    public ParentWindow(IFormFactory factory) // inject from IOC container 
    { 
    } 

    public void OpenChildWindow() 
    { 
     var child = _factory.CreateChildWindow(); 
     child.Show(); 
    } 
} 

但我的解決方案,我廠那種成爲我自己的IOC容器,我所有的家長窗口都必須通過工廠,這不是使我的工廠成爲新的「服務器定位器」。

有沒有其他更好的解決方案呢?

+0

相關:https://stackoverflow.com/questions/38417654/winforms-how-to-register-forms-with-ioc-container/38421425#38421425 – Steven

+0

@Steven不能解決我的問題 – LeY

回答

0

使用DI意味着你消耗的容器作爲服務定位器某處,優選在一行代碼,其執行一次。這被稱爲「組合根」,其中容器被配置並且對象圖的根被創建。

有了這個在你的榜樣mind-最上面的代碼不會違反這個原則。

旁註:

我一直做的是什麼包裝的容器框架代碼與我自己的類,這樣我可以切換直接投資框架更easily-考慮。

+0

使用DI doesn並不意味着直接消耗容器。它甚至可以被認爲是一種代碼味道,在整個堆棧中都具有顯式的依賴性。相反,通過組合根和本地工廠的組合,您可以只依賴容器的堆棧頂部,並在任何地方使用本地工廠,而不依賴於任何容器。 –

+0

我完全同意,這正是我所說的 - 如果你仔細閱讀 - 減去我沒有提及的當地工廠部分。 (編輯答案,這樣會更清楚)。 @WiktorZychla –

+0

請注意,CR只是故事的一半。你可以在那裏配置容器,但你不知何故需要將容器傳遞給堆棧。當地工廠的想法是另一半,使用當地的工廠,您不再需要參考集裝箱。 –

1

你建議的解決方案是在正確的方向邁出了一大步。工廠並不像一個定位器那樣聞起來,而是一個本地工廠,它屬於它的一部分。

更進一步的將是忘記工廠家族(接口)的想法,並有一個具有可插拔實現的具體工廠,它在內部使用一個容器(或不使用一個容器),但提供一個單一的API客戶端。這樣,您可以將工廠的構造函數注入到表單中,而只是使用工廠的具體類型。工廠本身在組合根中配置。

更多細節和代碼示例在我的博客文章

http://www.wiktorzychla.com/2016/01/di-factories-and-composition-root.html

0

第一個例子:我不喜歡,因爲你也有依賴性,你不能單元測試。它將解決ChildWindow的實例,並且您無法控制(模擬)它。

第二個例子:我不喜歡,因爲你正在使用類Container沒有接口。

第三個例子:它會工作比以前更好,有時我用工廠的這種方式。它可以完全通過單元測試。

通常我認爲這是更好地使用DI容器,工廠,因爲它提供了更多的功能,如例如物件壽命...

我從來沒有使用過類ChildWindow,但如果我不能在構造函數中定義的界面我更喜歡執行一些ChildWindowWrapper:IChildWindowWrapper並使用該包裝。它將進行簡單的單元測試,可以在DI容器中使用。

+0

您能否提供一些「使用DI容器作爲工廠」和「ChildWindowWrapper」的例子 – LeY

+0

@LeY如果聲音不明確,對不起。我想說,我寧願使用DI容器來創建對象的新實例,而不是使用Factory模式(方法)。例如,如果類沒有實現Interface或Abstract類,我將使用包裝類。包裝器是封裝您需要的某些功能的類。相反,直接在代碼中使用你的類,你將需要直接使用Wrapper。包裝將需要實現界面,您將能夠註冊您的DI容器。 – kat1330