Dependency injection 在Windows客户端(WPF)应用程序中执行依赖项注入的正确方法
我习惯于在web应用程序中使用IoC/DI,主要是使用MVC3的Ninject。我的控制器是为我创建的,用所有适当的依赖项、子依赖项等填充 但是,在厚客户端应用程序中情况就不同了。我必须创建我自己的对象,或者我必须恢复到服务定位器风格的方法,在这种方法中,我要求内核(可能通过一些接口,以允许可测试性)给我一个具有依赖性的完整对象 然而,我在几个地方看到服务定位器被描述为反模式 所以我的问题是——如果我想在我的厚客户端应用程序中受益于Ninject,有没有更好/更合适的方法来实现这一切Dependency injection 在Windows客户端(WPF)应用程序中执行依赖项注入的正确方法,dependency-injection,ninject,service-locator,testability,thick-client,Dependency Injection,Ninject,Service Locator,Testability,Thick Client,我习惯于在web应用程序中使用IoC/DI,主要是使用MVC3的Ninject。我的控制器是为我创建的,用所有适当的依赖项、子依赖项等填充 但是,在厚客户端应用程序中情况就不同了。我必须创建我自己的对象,或者我必须恢复到服务定位器风格的方法,在这种方法中,我要求内核(可能通过一些接口,以允许可测试性)给我一个具有依赖性的完整对象 然而,我在几个地方看到服务定位器被描述为反模式 所以我的问题是——如果我想在我的厚客户端应用程序中受益于Ninject,有没有更好/更合适的方法来实现这一切 可测试性
- 可测试性
- 适当的DI/IoC
- 尽可能少的耦合
TL;DR:对于客户端来说,交付一个结构合理的API太麻烦了。我的API需要交付一个单独的对象——使用DI和适当的实践在幕后构建——供他们使用。有时,现实世界压倒了向后构建一切以保持模式和实践真实性的愿望。我对WPF或MVVM一无所知,但您的问题基本上是如何在不使用服务定位器(或直接使用容器)的情况下从容器中取出内容,对吗?
如果是,我可以给你举个例子 关键是您使用的是一个工厂,它在内部使用容器。这样,您实际上只在一个地方使用容器 注意:我将使用WinForms的一个示例,并且没有绑定到特定的容器(因为,正如我所说,我不知道WPF…并且我使用Castle Windsor而不是NInject),但是由于您的基本问题没有具体绑定到WPF/NInject,所以您应该很容易将我的答案“移植”到WFP/NInject 工厂是这样的:
public class Factory : IFactory
{
private readonly IContainer container;
public Factory(IContainer container)
{
this.container = container;
}
public T GetStuff<T>()
{
return (T)container.Resolve<T>();
}
}
当应用程序启动时,容器被初始化,主窗体被解析(因此它通过构造函数注入获得工厂)
我建议看看Caliburn之类的MVVM框架。它们提供了与IoC容器的集成
基本上,您应该在app.xaml中构建完整的应用程序。如果某些部件需要稍后创建,因为您还不知道在启动时创建它们的所有内容,那么可以将工厂作为接口(请参见下文)或Func(请参见)注入到需要创建此实例的类中。在下一个Ninject版本中,这两种技术都将得到本机支持 e、 g
公共接口IFooFactory{IFoo CreateFoo();}
公共类FooFactory:IFooFactory
{
私有IKernel内核;
食品工厂(IKernel内核)
{
this.kernel=内核;
}
公共ifoocreatefoo()
{
this.kernel.Get();
}
}
请注意,工厂实现在逻辑上属于容器配置,而不是业务类的实现。-1您的
GetStuff()
是一个穿着连衣裙的服务定位器。不要这样做。(你剩下的答案没有错,但狡猾让我觉得很有趣)甚至在看到雷莫的答案(我认为这是正确的方法)之前,我就打算建议工厂注资(在适当的情况下作为Funcs a la)
public partial class MainForm : Form
{
private readonly IFactory factory;
public MainForm(IFactory factory)
{
this.factory = factory;
InitializeComponent(); // or whatever needs to be done in a WPF form
}
}
static class Program
{
static void Main()
{
var container = new Container();
container.Register<MainForm>();
container.Register<IFactory, Factory>();
container.Register<IYourRepository, YourRepository>();
Application.Run(container.Resolve<MainForm>());
}
}
var repo = this.factory.GetStuff<IYourRepository>();
repo.DoStuff();
var form = this.factory.GetStuff<IAnotherForm>();
form.Show();
public partial class MainForm : Form
{
private readonly IAnotherForm form;
// pass AnotherForm via constructor injection
public MainForm(IAnotherForm form)
{
this.form = form;
InitializeComponent(); // or whatever needs to be done in a WPF form
}
// open AnotherForm
private void Button1_Click(object sender, EventArgs e)
{
this.form.Show();
}
}
public partial class AnotherForm : Form
{
private readonly IRepository repo;
// pass the repository via constructor injection
public AnotherForm(IRepository repo)
{
this.repo= repo;
InitializeComponent(); // or whatever needs to be done in a WPF form
// use the repository
this.repo.DoStuff();
}
}
public interface IFooFactory { IFoo CreateFoo(); }
public class FooFactory : IFooFactory
{
private IKernel kernel;
FooFactory(IKernel kernel)
{
this.kernel = kernel;
}
public IFoo CreateFoo()
{
this.kernel.Get<IFoo>();
}
}