Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cyclic reference issue in MVP pattern using Windsor castle for Dependency injection

I am facing a problem of cyclic dependency when creating the following MVP design (for winforms) using windsor container.

My presenter depends on the view and model:

ConcretePresenter(IView view, IModel model)
{
    this.view = view;
    this.model = model;
}

My view depends on the presenter:

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

I am registering all components using Windsor castle (in a separate composition root class) as below:

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

Resolving the View brings up the issue of cyclic reference issue:

container.Resolve<ConcreteView>(); //doesn't resolve because of cyclic dependency

A possible solution would be to remove the constructor injection from the view and resolve the presenter separately. But this causes me to use the container in two places which i was not looking to do and probably is wrong.

ConcreteView()
{
    container.Resolve<ConcretePresenter>(); //resolving at 2 different points       
}

Is there any better solution to this. Am I doing something wrong in MVP itself?

like image 597
nikhil pinto Avatar asked Dec 20 '12 13:12

nikhil pinto


1 Answers

There are several solutions to this problem, but all of them break the dependency cycle by removing either the presenter or the view from as constructor dependency.

The easiest solution would be by introducing the view as property on the presenter:

// Presenter
ConcretePresenter(IModel model)
{
    this.model = model;
}

public IView View { get; set; }

// View
ConcreteView(ConcretePresenter presenter)
{
    this.presenter = presenter;
    this.presenter.View = this;
}

Downside of this is that you need to configure each presenter as it is injected into the view, so you could also move this to a base class:

// View
ConcreteView(ConcretePresenter presenter) : base(presenter)
{
}

BaseView(IPresenter presenter)
{
    Contract.Requires(presenter != null);
    presenter.View = this;
    this.Presenter = presenter;
}

Another option is to inject a presenter factory into the view and request it from there:

// View
ConcreteView(IPresenterFactory factory)
{
    this.presenter = factory.CreatePresenterFor(this);
}

Downside is that this constructor calls a factory, which is not the cleanest thing to do, but manageable.

like image 105
Steven Avatar answered Sep 24 '22 14:09

Steven