IoC / DI容器,工厂和运行时类型创建

时间:2012-03-09 00:36:54

标签: c# java design-patterns language-agnostic dependency-injection

我最近了解了DI框架Guice和Ninject,并希望在我的一些新项目中使用它们。

虽然我熟悉一般依赖注入概念并且知道如何使用这些框架来构建对象图,但是当涉及动态应用程序行为时,我很难应用IoC。

考虑这个例子:

  • 当应用程序启动时,将显示主窗口。
  • 当用户点击主面板时,会打开一个上下文菜单。
  • 取决于用户选择,将创建用户控件并显示在鼠标位置。
  • 如果用户最终决定关闭该应用程序,将显示一个确认框,并在确认后关闭主窗口。

虽然很容易将主窗口的View连接到Presenter / ViewModel,然后将其绑定到域逻辑,但我不明白如何干净地(在IoC意义上)实现以下任务:

  • 动态实例化具体的UI控件(例如IGreenBoxViewIRedImageView< - JConcreteGreenBoxViewJConcreteRedImageView),而不使用任何类型的服务定位器模式(例如再次从IoC请求)
    • 根据具体情况,创建新模型,演示者和视图实例
  • 类似地,实例化一个新的具体对话框,例如:运行时JOptionPane

我见过一些使用抽象工厂的解决方案,但老实说并没有完全理解它们。似乎这样的解决方案会导致将一些(查看域名,presenter域名,......)内部类型暴露给构造根,并随之暴露给整个世界。

那么 - 我该怎么做呢?

2 个答案:

答案 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的答案分享)