使用windsor容器创建以下MVP设计(用于winforms)时,我遇到循环依赖问题。
我的演示者取决于视图和模型:
ConcretePresenter(IView view, IModel model)
{
this.view = view;
this.model = model;
}
我的观点取决于演示者:
ConcreteView(ConcretePresenter presenter)
{
//actual requirement that the presenter use the current instance of the view and a model object
//new presenter(this, new model())
this.presenter = presenter;
}
我正在使用Windsor城堡(在单独的合成根类中)注册所有组件,如下所示:
IWindsorContainer container;
container = new WindsorContainer();
container.Register(Component.For<ConcretePresenter>().ImplementedBy<ConcretePresenter>());
container.Register(Component.For<IModel>().ImplementedBy<ConcreteModel>());
container.Register(Component.For<IView>().ImplementedBy<ConcreteView>());
解决视图会出现循环引用问题:
container.Resolve<ConcreteView>(); //doesn't resolve because of cyclic dependency
一种可能的解决方案是从视图中删除构造函数注入并单独解析presenter。 但这导致我在两个地方使用容器,我不打算这样做,可能是错误的。
ConcreteView()
{
container.Resolve<ConcretePresenter>(); //resolving at 2 different points
}
有没有更好的解决方案。我在MVP中做错了吗?
答案 0 :(得分:4)
这个问题有几个解决方案,但是它们都通过从构造函数依赖项中删除presenter或视图来打破依赖循环。
最简单的解决方案是将视图作为属性引入演示者:
// Presenter
ConcretePresenter(IModel model)
{
this.model = model;
}
public IView View { get; set; }
// View
ConcreteView(ConcretePresenter presenter)
{
this.presenter = presenter;
this.presenter.View = this;
}
这样做的缺点是,您需要在将每个演示者注入视图时对其进行配置,因此您也可以将其移动到基类:
// View
ConcreteView(ConcretePresenter presenter) : base(presenter)
{
}
BaseView(IPresenter presenter)
{
Contract.Requires(presenter != null);
presenter.View = this;
this.Presenter = presenter;
}
另一个选择是将一个演示者工厂注入视图并从那里请求它:
// View
ConcreteView(IPresenterFactory factory)
{
this.presenter = factory.CreatePresenterFor(this);
}
缺点是这个构造函数调用了一个工厂,这不是最干净的工作,但是可以管理。
答案 1 :(得分:0)
创建工厂以实例化演示者。您的视图(WinForm)将使用构造函数中的工厂。您可以使用Typed Factory Facility - 这意味着您只需要为演示者工厂定义接口,然后让工厂完成剩下的工作。