2016-09-28 47 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