Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Presenter injection in Model-View-Presenter pattern with StructureMap

I've implemented my own copy of the model view presenter pattern (in vein of web client software factory) so I can leverage my own DI framework instead of being tied to WCSF's ObjectBuilder which I had numerous problems with. I've come up with a few ways to do it but none of them particularly make me happy. I wanted to know if anyone else had some other ideas.

Solution #1a

Uses a HttpModule to intercept context.PreRequestHandlerExecute to call ObjectFactory.BuildUp(HttpContext.Current.Handler)

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

Solution #1b

Call buildup in page load instead of using a HttpModule

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        ObjectFactory.BuildUp(this);
    }
}

Solution #1c

Access presenter through Property allow Getter to BuildUp if needed.

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    public EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                ObjectFactory.BuildUp(this);
            }

            return _presenter;
        }
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

Solution #2

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                _presenter = ObjectFactory.GetInstance<EmployeePresenter>();
                _presenter.View = this;
            }

            return _presenter;
        }
    }
}

Solution #2b

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                Presenter = ObjectFactory.GetInstance<EmployeePresenter>();
            }

            return _presenter;
        }
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

Edit: Added solution 1c, 2b

like image 296
Chris Marisic Avatar asked Feb 05 '09 05:02

Chris Marisic


1 Answers

I'd Use solution #1b, and create a layer supertype for all the pages, in order to DRY the presenter initialization a bit more. like this:

Page code:

public partial class _Default : AbstractPage, IEmployeeView
{
    private EmployeePresenter presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            presenter = value;
            presenter.View = this;
        }
    }
    protected override void Do_Load(object sender, EventArgs args)
    {
        //do "on load" stuff 
    }

}

Abstract Page code:

public abstract class AbstractPage : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ObjectFactory.BuildUp(this);
        this.Do_Load(sender,e); 
        //template method, to enable subclasses to mimic "Page_load" event

    }
    //Default Implementation (do nothing)
    protected virtual void Do_Load(object sender, EventArgs e){}
}

With this solution you have the presenter initialization (created by the ObjectFactory) in one class only, if you need to modify it later you can do it easily.

Edit:

Should Do_Load be abstract or virtual ?

Template Method originally states that the method should be Abstract, in order to force subclasses to implement it, adhering to the superclass contract. (see wikipedia example of "Monopoly" < "Game").

On the other hand in this particular case, we don't want to force the user class to redefine our method, but give it the chance to do so. If you declare it abstract, many classes will be obliged to redefine the method just to leave it empty (this is clearly a code smell). So we provide a sensible default (do nothing) and make the method virtual.

like image 79
Pablo Fernandez Avatar answered Sep 28 '22 15:09

Pablo Fernandez