我最近了解了DI框架Guice和Ninject,并希望在我的一些新项目中使用它们。
虽然我熟悉一般依赖注入概念并且知道如何使用这些框架来构建对象图,但是当涉及动态应用程序行为时,我很难应用IoC。
考虑这个例子:
虽然很容易将主窗口的View连接到Presenter / ViewModel,然后将其绑定到域逻辑,但我不明白如何干净地(在IoC意义上)实现以下任务:
IGreenBoxView
,IRedImageView
< - JConcreteGreenBoxView
,JConcreteRedImageView
),而不使用任何类型的服务定位器模式(例如再次从IoC请求)
JOptionPane
我见过一些使用抽象工厂的解决方案,但老实说并没有完全理解它们。似乎这样的解决方案会导致将一些(查看域名,presenter域名,......)内部类型暴露给构造根,并随之暴露给整个世界。
那么 - 我该怎么做呢?
答案 0 :(得分:4)
如果可以重用控件,那么可以在使用它们的地方进行构造函数注入。否则你必须注入工厂:
public interface IControlFactory
{
IGreenBoxView CreateGreenBoxView();
IRedImageView CreateRedImageView();
}
并将其注入您需要创建此控件的位置。
实现转到容器配置。在那里,您可以将容器注入实现。一些容器提供自动实现此工厂。例如,在Ninject:
Bind<IControlFactory>().ToFactory();
请参阅https://github.com/ninject/ninject.extensions.factory/wiki
答案 1 :(得分:0)
对于那些希望用 Unity (而不是Ninject)做类似事情的人,我创建了一个扩展,允许你创建工厂,甚至不需要声明接口:UnityMappingFactory@GitHub < / p>
您只需在正常的引导过程中将注册添加到您注册类的位置......
//make sure to register the output...
container.RegisterType<IImageWidgetViewModel, ImageWidgetViewModel>();
container.RegisterType<ITextWidgetViewModel, TextWidgetViewModel>();
//define the mapping between different class hierarchies...
container.RegisterFactory<IWidget, IWidgetViewModel>()
.AddMap<IImageWidget, IImageWidgetViewModel>()
.AddMap<ITextWidget, ITextWidgetViewModel>();
然后,您只需在CI的构造函数中声明映射工厂接口,并使用其 Create()方法...
public ImageWidgetViewModel(IImageWidget widget, IAnotherDependency d) { }
public TextWidgetViewModel(ITextWidget widget) { }
public ContainerViewModel(object data, IFactory<IWidget, IWidgetViewModel> factory)
{
IList<IWidgetViewModel> children = new List<IWidgetViewModel>();
foreach (IWidget w in data.Widgets)
children.Add(factory.Create(w));
}
作为额外的好处,映射类的构造函数中的任何其他依赖项也将在对象创建期间得到解析。 (也作为这个Stackoverflow post的答案分享)