我目前正在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/