Model View Presenter - with base functionality

Lately I've been doing a lot of research and development around patterns and unit testing.  One pattern in particular, Model View Presenter (MVP), I found to be a very good pattern for doing web development.  The only thing, is that if you want to learn about the MVP, there seem to be two options.  1)  Completely theoretical in which you talk about the design and what its supposed to accomplish or 2) Simple - very simple examples on how to use the MVP - that doesn't show how to expand the pattern.  So, I thought I would give it a shot to write about a more complex MVP pattern to try to handle real world scenarios.

Here's some requirements for this example:

  1. Have a control library to handle generic/default implementations
  2. Have different implementations of the same control, but not have to re-write a ton of the logic.
  3. Server controls will write out their properties.
  4. Animals with different two (or N) types.  For this example I'll use Dog and Cat.

Lets get started:

I start off by creating a new Control Library project that contains 3 controls:

  1. Animal Control - this will contain the default behavior
  2. Dog Control - this will have dog specific behavior
  3. Cat Control - this will have cat specific behavior

I'll start with the Animal Control.  The first thing I want to do is define my interface, I do so by creating a structure that looks like this:

namespace MVP_Example

{

    public interface IAnimalView

    {

        string MyNoise { get; set; }

        string MyHappyGesture { get; set; }

    }

}

I then create my Animal Control using the new interface and inheriting from WebControl.  This is the main control that handles most of the details I would like to display, and the main implementation of the view.  I added comments into the code to explain what I'm doing:

namespace MVP_Example

{

    public class AnimalControl : WebControl, IAnimalView

    {

        private AnimalPresenter _presenter;

        private string _myNoise;

        private string _myHappyGesture;

 

        protected override void OnInit(EventArgs e)

        {

            base.OnInit(e);

 

            //pass in this control (the view) to the presenter

            _presenter = new AnimalPresenter(this);

        }

        protected override void Render(HtmlTextWriter writer)

        {

 

            //Here I custom render myself

            writer.RenderBeginTag(HtmlTextWriterTag.P);

            //output my noise property as defined in the view

            writer.Write(string.Format("My Noise is {0}", MyNoise));

            writer.RenderEndTag();

 

            writer.RenderBeginTag(HtmlTextWriterTag.P);

            //output my gesture property as defined in the view

            writer.Write(string.Format("I'm happy by {0}", MyHappyGesture));

            writer.RenderEndTag();

 

        }

 

        #region IAnimalView Members

 

        public string MyNoise

        {

            get

            {

                return _myNoise;

            }

            set

            {

                _myNoise = value;

            }

        }

 

        public string MyHappyGesture

        {

            get

            {

                return _myHappyGesture;

            }

            set

            {

                _myHappyGesture = value;

            }

        }

 

        #endregion

    }

}

For my Animal Control I also have the presenter which sets up the default values:

namespace MVP_Example

{

    public class AnimalPresenter

    {

        private IAnimalView _view;

 

        public AnimalPresenter(IAnimalView view)

        {

            _view = view;

            _view.MyNoise = "Making Noise";

            _view.MyHappyGesture = "Wagging My Tail";

        }

    }

}

Next, I want to use that Animal Control, but for my dog control it barks as a noise, so I want to override that property.  I inherit from the Animal Control to get the implementation of IAnimalView that I just coded.  The only difference is that I have a special DogPresenter that inherits from Animal Presenter so that I can use that functionality that I already coded.  You'll notice how empty the control is, and that is good because you have all your logic where it should be!

Here is the Dog Control:

namespace MVP_Example

{

    public class DogControl : AnimalControl

    {

        private DogPresenter _presenter;

 

        protected override void OnInit(EventArgs e)

        {

            base.OnInit(e);

            _presenter = new DogPresenter(this);

        }

    }

}

Here is my Dog Presenter:

namespace MVP_Example

{

    public class DogPresenter : AnimalPresenter

    {

        private IAnimalView _view;

 

        public DogPresenter(IAnimalView view)

            : base(view)

        {

            _view = view; // get the view from the control

 

            // add my own special noise, but keep the generic animal gesture

            _view.MyNoise = "Bark";

        }

    }

}

I do the same with the Cat Control:

namespace MVP_Example

{

    public class CatControl : AnimalControl

    {

        private CatPresenter _presenter;

 

        protected override void OnInit(EventArgs e)

        {

            base.OnInit(e);

            _presenter = new CatPresenter(this);

        }

    }

}

Now with the cat presenter, it has its own noise and gesture, so I override those: 

namespace MVP_Example

{

    public class CatPresenter : AnimalPresenter

    {

        private IAnimalView _view;

 

        public CatPresenter(IAnimalView view)

            : base(view)

        {

            _view = view; // get the view from the control

            _view.MyNoise = "Meow"; // add my own special noise

            _view.MyHappyGesture = "Purring"; //I have my own happy gesture

        }

    }

}

Now to display these I just add a reference to the control library and add the controls to the page (here are just the lines I added to the aspx):

<%@ Register Assembly="MVP_Example" Namespace="MVP_Example" TagPrefix="animal" %>

<strong>animal: </strong><animal:AnimalControl runat="server" />

<strong>dog: </strong><animal:DogControl runat="server" />

<strong>cat: </strong><animal:CatControl runat="server" />

And the output is as follows:

animal:

My Noise is Making Noise

I'm happy by Wagging My Tail

dog:

My Noise is Bark

I'm happy by Wagging My Tail

cat:

My Noise is Meow

I'm happy by Purring

There are a few different ways to accomplish some major tasks and having your base functionality isolated and then use that base functionality in other classes.  With the MVP pattern you can pull out the logic from the user interface and keep it in the presenters.  The example from above with the inheritance is extremely useful if you have a lot of data to get off the http request everytime, such as the url query string items, etc.  Having unique implementations of the presenter for your controls is useful for having your own databinding implementations, etc.

Download the code: http://brob.members.winisp.net/MVP_Example.zip (Example was created with VS 2008 Beta 2)