我目前正在WinForms系统上工作(我知道),在创建表单时会有很多Constructor Injection,但是如果这些表单/视图需要打开另一个表单,我发现DI容器也已注入,因此我们可以在运行时找到所需视图接口的实现。例如

public partial class MyView : Form, IMyView
{
    private readonly IDIContainer _container;

    public MyView(IDIContainer container)
    {
        InitializeComponent();

        _container = container;
    }

    public OpenDialogClick(object sender, EventArgs e)
    {
        var dialog = container.Resolve<IDialogView>();
        dialog.ShowDialog(this);
    }
}


我知道这基本上是将容器用作服务定位器。我一再被告知这被认为是反模式,因此我想避免这种用法。

我可能会像这样将视图作为构造函数的一部分注入:

public partial class MyView : Form, IMyView
{
    private readonly IDialogView _dialog;

    public MyView(IDialogView dialog)
    {
        InitializeComponent();

        _dialog = dialog;
    }

    public OpenDialogClick(object sender, EventArgs e)
    {
        dialog.ShowDialog(this);
    }
}


但是,如果对话框视图的实例化非常昂贵怎么办?

有人建议我们创建某种形式的表单工厂,该表单工厂在内部使用DI容器,但是对我来说,这似乎只是在另一个服务定位器周围创建包装器。

我知道在某个时候,有些事情必须知道如何创建IDialogView,所以我在想,要么在创建复合根时就解决了它(如果存在很多形式,并且某些或全部创建成本很高,可能就不理想了) ,或者复合根本身可以解决依赖关系。在哪种情况下,复合根必须具有类似服务定位器的依赖关系?但是子窗体将如何创建这样的对话框?他们会通过事件调用组合程序来打开这样的对话框吗?

我一直面临的一个特殊问题是,几乎不可能轻松模拟容器。这就是让我思考表单工厂想法的部分原因,即使它只是包装容器的包装。这是明智的原因吗?

我以为自己陷入了困境吗?有没有简单的方法可以解决这个问题?还是我只是打个结,找到对我有用的东西?

最佳答案

还是我只是打个结,找到对我有用的东西?


工厂类别:

public interface IDialogFactory {
    IDialogView CreateNew();
}

// Implementation
sealed class DialogFactory: IDialogFactory {
   public IDialogView CreateNew() {
      return new DialogImpl();
   }
}

// or singleton...
sealed class SingleDialogFactory: IDialogFactory {
   private IDialogView dialog;
   public IDialogView CreateNew() {
      if (dialog == null) {
         dialog = new DialogImpl();
      }
      return dialog;
   }
}

Your code:

public partial class MyView : Form, IMyView {
   private readonly IDialogFactory factory;
   public MyView(IDialogFactory factory) {
      InitializeComponent();
      //assert(factory != null);
      this.factory = factory;
   }

   public OpenDialogClick(object sender, EventArgs e) {
      using (var dialog = this.factory.CreateNew()) {
         dialog.ShowDialog(this);
      }
   }
}

Registration with SimpleInjector

container.RegisterSingle<IDialogFactory, DialogFactory>();


或使用单例版本

container.RegisterSingle<IDialogFactory, SingleDialogFactory>();

container.RegisterSingle<IMyView, MyView>();

关于c# - 如何避免服务定位器模式?我是不是该?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21048886/

10-13 03:36