如何避免Service Locator模式?我是不是该? [英] How do I avoid the service locator pattern? Should I?

查看:155
本文介绍了如何避免Service Locator模式?我是不是该?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前工作的一个WinForms系统(我知道)创建表单时,那里有很多的构造器注入对的,但如果这些表单/视图需要另辟形式,我觉得DI容器已经注射过,使我们可以在运行时找到所需的视图接口的实现。 。例如

 公共部分类MyView的:形式,IMyView 
{
私人只读IDIContainer _container;

公共MyView的(IDIContainer容器)
{
的InitializeComponent();

_container =容器;
}

公共OpenDialogClick(对象发件人,EventArgs五)
{
VAR对话框= container.Resolve< IDialogView>();
dialog.ShowDialog(本);
}
}



我知道,这基本上是使用容器作为一个服务定位器。我已经多次告诉我,这被认为是一种反模式,所以我想避免这种用法。



我大概可以注入视图作为构造的一部分像这样的:

 公共部分类MyView的:形式,IMyView 
{
私人只读IDialogView _dialog;

公共MyView的(IDialogView对话)
{
的InitializeComponent();

_dialog =对话框;
}

公共OpenDialogClick(对象发件人,EventArgs五)
{
dialog.ShowDialog(本);
}
}



但是,如果对话框的看法是相当昂贵实例?



它已经建议我们创建某种形式的工厂内部使用的DI容器,但对我来说这似乎是简单地创建围绕另一个服务定位器的包装。



我知道,在某些时候,的的东西的必须知道如何创建一个IDialogView,所以我想,要么它解决了当复合根创建(可能不是如果理想有许多形式和部分或全部是创建昂贵),或复合根本身具有的方式来解决的依赖性。在这种情况下,该复合根必须具有服务定位器状依赖?但后来怎么会子窗体创建这样的对话?将它们通过,比方说,事件,打开对话框这样调用到复合



我一直针对运行起来的一个特殊问题是,容器是几乎不可能嘲笑容易。这部分是什么让我思考形式工厂的想法,即使它只是是容器周围的包装。那是一个合理的理由吗?



我也曾想过自己变成一个结?有没有通过这个简单的方法吗?或者,我只是削减结和找到的东西,对我的作品?


解决方案

还是我?刚切结,找到的东西,为我的作品




工厂类:

 
公共接口IDialogFactory {
IDialogView CreateNew();
}

//执行
密封类DialogFactory:IDialogFactory {
公共IDialogView CreateNew(){
返回新DialogImpl();
}
}

//或单身...
密封类SingleDialogFactory:IDialogFactory {
私人IDialogView对话框;
公共IDialogView CreateNew(){
如果(对话== NULL){
=对话框新DialogImpl();
}
返回对话框;
}
}

您的代码:

 
公共部分类MyView的:形式,IMyView {
私人只读IDialogFactory厂;
公共MyView的(IDialogFactory工厂){
的InitializeComponent();
//断言(出厂!= NULL);
this.factory =厂;
}

公共OpenDialogClick(对象发件人,EventArgs e)利用{
(VAR对话框= this.factory.CreateNew()){
dialog.ShowDialog(这);
}
}
}



与注册的 SimpleInjector

  container.RegisterSingle< IDialogFactory,DialogFactory>(); 

或使用单版本

  container.RegisterSingle< IDialogFactory,SingleDialogFactory>(); 

container.RegisterSingle< IMyView,MyView的>();


I'm currently working on a WinForms system (I know) where there's a lot of Constructor Injection when creating forms, but if those forms/views need to open another form, I find the DI container has been injected too so that we can locate the implementation of the desired view interface at runtime. e.g.

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);
    }
}

I'm aware that this is basically using the container as a service locator. I've been repeatedly told that this is considered an anti-pattern so I'd like to avoid this usage.

I could probably inject the view as part of the constructor like 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);
    }
}

But what if the dialog view is quite expensive to instantiate?

It's been suggested that we create some kind of form factory which internally uses the DI container, but to me this seems like simply creating a wrapper around another service locator.

I know that at some point, something has to know how to create an IDialogView, so I'm thinking that either it's resolved when the composite root is created (probably not ideal if there are many forms and some or all are expensive to create), or the composite root itself has a way to resolve the dependency. In which case the composite root has to have a service-locator-like dependency? But then how would child forms create dialogs like this? Would they call up to the composite via, say, events, to open dialogs like this?

One particular problem I keep running up against is that the container is almost impossible to mock easily. This is partly what keeps me thinking about the form factory idea, even though it would just be a wrapper around the container. Is that a sensible reason?

Have I thought myself into a knot? Is there a simple way through this? Or do I just cut the knot and find something that works for me?

解决方案

Or do I just cut the knot and find something that works for me?

Factory class:

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>();

or using singleton version

container.RegisterSingle<IDialogFactory, SingleDialogFactory>();

container.RegisterSingle<IMyView, MyView>();

这篇关于如何避免Service Locator模式?我是不是该?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆