Build your own CAB Part #5 – The Presentation Model

Our four friends are crafting a strategy for the inevitable and highly anticipated clash with the minions of the Lady de Winter.  Mighty Porthos has just finished a long oration about his Passive View approach to creating maintainable WinForms screens.  The crafty Aramis has started his own oratory on his preferred approach to avoid so much Interaction Based Testing by utilizing…

 

The Presentation Model

The Presentation Model differs from the two Model View Presenter approaches (Supervising Controller and Passive View) by combining the “M” and the “P” into a single class.  This single Presentation Model class both contains the state of the screen and implements the behavior of the screen.  Compared to the Supervising Controller, Presentation Model is more complex in that it also implements the state of the screen, but also less complex because the state synchronization is almost entirely the responsibility of the View itself.  Instead of a Presenter directing the View to change the state of the screen, the Presentation Model simply changes its own state and depends on Data Binding (or an equivalent) to update the screen accordingly. 

Let’s jump right into our third and final implementation of the Shipping Screen.  As I stated before, the View will use data binding to bind its screen elements to the public properties on the new ScreenPresentationModel class.

    public partial class ShippingScreen : Form

    {

        public ShippingScreen()

        {

            InitializeComponent();

        }

 

        public void Bind(ShippingPresentationModel model)

        {

            shipmentBindingSource.DataSource = model;

        }

    }

I’ll spare you the rest of the data binding setup code, and besides, that’s covered in other literature to a vastly greater degree than Presentation Model.  Besides which, I’ve barely worked with data binding and you’ve probably guessed correctly that I’m more than a little biased against it.

So far we haven’t seen anything that different from Supervising Controller, but when you use the Presentation Model approach you’re probably exploiting the fact that data binding in WinForms can also bind to the “Visible” and “Enabled” properties of controls and not just the value.  In the case of the Shipping screen, we’ll bind the “Enabled” properties of the checkbox’s for selecting insurance and requiring a signature to properties on the ShippingPresentationModel shown below.

        public bool InsuranceEnabled

        {

            get { return _insuranceEnabled; }

            set { _insuranceEnabled = value; }

        }

 

        public bool SignatureEnabled

        {

            get { return _signatureEnabled; }

            set { _signatureEnabled = value; }

        }

 

        public string Vendor

        {

            get { return _vendor; }

            set

            {

                _vendor = value;

                fireChanged(“Vendor”);

 

                DeliveryOptions options = _service.GetDeliveryOptions(this);

                InsuranceEnabled = options.PurchaseInsuranceEnabled;

                SignatureEnabled = options.RequireSignatureEnabled;

            }

        }

In the above code, anytime a user selects a different shipping vendor the data binding will call the setter for Vendor on ShippingPresentationModel, causing a recalculation of the InsuranceEnabled and SignatureEnabled properties, which finally causes the two checkbox’s to be either enabled or disabled depending upon the shipping vendor selected.  All because a little bug went kachooo!

The communication between View and the Presentation Model is relatively simple, the View simply sets properties on the PresentationModel class and cascading actions are triggered in the setters.  I’ve purposely put off talking about View to Presenter communication, but let’s just say that this aspect of the Presentation Model is simpler than either Supervising Controller or Passive View.

One last example of the ShippingPresentationModel.  There are three or four factors that influence the cost of the shipment.  If any of these screen elements change, the cost needs to reevaluated.  With Presentation Model, I just capture all change events inside the setters, so the trigger to reevaluate the shipping cost is something like this:

        public string ShippingOption

        {

            get { return _shippingOption; }

            set

            {

                _shippingOption = value;

                fireChanged(“ShippingOption”);

 

                _service.CalculateCost(this);

            }

        }

 

        public bool PurchaseInsurance

        {

            get { return _purchaseInsurance; }

            set

            {

                _purchaseInsurance = value;

                fireChanged(“PurchaseInsurance”);

 

                _service.CalculateCost(this);

            }

        }

 

        public bool RequireSignature

        {

            get { return _requireSignature; }

            set

            {

                _requireSignature = value;

                fireChanged(“RequireSignature”);

 

                _service.CalculateCost(this);

            }

        }

I simply make a call to IShippingService.CalculateCost(IShipment) anytime a property changes that impacts the shipping calculation.  For convenience sake, I made ShippingPresentationModel implement a common IShipment interface that is consumed by IShippingService, if you’re wondering where in the world the “this” parameter was coming from.  I’m assuming that the IShippingService will itself set the IShipment.Cost property.  The signatures for IShippingService still looks like this:

    public interface IShippingService

    {

        string[] GetLocations();

        string[] GetShippingVendorsForLocation(string location);

        string[] GetShippingOptions(IShipment shipment);

        void CalculateCost(IShipment shipment);

        DeliveryOptions GetDeliveryOptions(IShipment shipment);

    }

State Based Unit Testing

The biggest difference to me in using Presentation Model versus one of the MVP patterns is the shift to state based testing inside of our xUnit tests.  I’m more or less a “mockist” I guess, but I’ve worked with more than a few people who’ve had almost allergic reactions to using mock objects.  If you’re one of those people, don’t worry, you’re not out of luck because you can do more or less state based testing with Presentation Model.  Here’s an example of what I mean (even though out of pure contrariness I’m using RhinoMocks to create my stub):

        [Test]

        public void ResetTheShippingOptionsWhenTheStateOrProvinceIsChanged()

        {

            // We’re going to test ShippingPresentationModel in a state-based manner

            // I’m using RhinoMocks to create the stub just because

            //   a.)  It’s easy

            //   b.)  I hate cluttering up the code with static mocks and stubs if

            //        I don’t have to.

 

            // You might note that I’m not even bothering to call mocks.VerifyAll()

 

            MockRepository mocks = new MockRepository();

            IShippingService service = mocks.CreateMock<IShippingService>();

            ShippingPresentationModel model = new ShippingPresentationModel(service);

 

            string[] theOptions = new string[]{“Option 1″, “Option 2″, “Option 3″};

            Expect.Call(service.GetDeliveryOptions(model)).Return(theOptions).Repeat.Any();

            mocks.ReplayAll();

 

            // We need to verify that the model starts with a zero array string

            Assert.AreEqual(0, model.ShippingOptions.Length);

 

            // I’m not sure I’d bother testing the raising of the PropertyChanged event,

            // or at least do it in another test.

            bool propertyWasCalled = false;

            model.PropertyChanged += delegate (object sender, System.ComponentModel.PropertyChangedEventArgs e)

                                        {

                                            propertyWasCalled = e.PropertyName == “ShippingOptions”;

                                        };

 

            model.StateOrProvince = “TX”;

 

            // Check that the state of the model changed

            Assert.AreEqual(theOptions, model.ShippingOptions);

 

            // And while we’re at it, let’s check that the PropertyNotified event was called

            Assert.IsTrue(propertyWasCalled);

        }

All I’m testing here is that the ShippingPresentationModel gets a list of Shipping Options whenever the StateOrProvince property is changed, then resets its ShippingOptions property.  I’m not real wild about it, but I also showed using an anonymous delegate to check that the PropertyChanged event was fired for “ShippingOptions.”  To recap, the expected sequence of events is:

  1. The user selects a value in the State or Province select box.
  2. Data binding in the view sets the StateOrProvince property on ShippingPresentationModel.  Since the View is just talking directly to getters and setters, we really don’t need the View involved in this unit test at all.
  3. In the setter for StateOrProvince, the ShippingPresentationModel should find the ShippingOptions for the selected state or province and set it’s internal value for ShippingOptions which…
  4. Fires the PropertyChanged event for “ShippingOptions” which directs the magical data binding support to fill the dropdown list for Shipping Options with new values (which I didn’t show because it’s documented very well on MSDN).

Whew.  The code that implements this test above is much simpler:

 

 

        public string StateOrProvince

        {

            get { return _stateOrProvince; }

            set

            {

                _stateOrProvince = value;

 

                // Whenever this property changes, we need to reset the

                // ShippingOptions to match the StateOrProvince

                ShippingOptions = _service.GetShippingOptions(this);

 

                fireChanged(“StateOrProvince”);

            }

        }

 

 

        public string[] ShippingOptions

        {

            get { return _shippingOptions; }

            set

            {

                _shippingOptions = value;

                fireChanged(“ShippingOptions”);

            }

        }

 

 

 

Summary

The Presentation Model is another example of a Humble View.  It largely differs from the Model View Presenter patterns by combining the Model and Presenter into a single class.  It’s important to note that the Presentation Model most likely encapsulates the actual application model, and it’s definitely part of the user interface rather than a domain model class implementing pure business logic.  While it does a great job isolating behavior from the View and exposing the behavior in a way that allows for state based testing, you might find yourself getting annoyed at all the delegation that has to take place between the Presentation Model class and the inner application model.  Then again, a buffer between the user interface and the rest of the application might just be a good thing.

Honestly, I haven’t used this pattern but a time or two.  The largest implementation I’ve seen was actually a Java Swing client where it was used quite effectively. 

I do have an example from StoryTeller that I will probably use in the posts on creating an Application Shell where I use Presentation Model as a kind of state machine to synchronize menu state as the screen mode changes.  I’m leaving it out now for the sake of brevity (and my impending bedtime).

Other Resources

  • I think Presentation Model is another name for the Model/View/ViewModel pattern being promoted by some of the WPF team at Microsoft.  I still think I’d rather stick with Supervising Controller in most cases, but I’m thrilled that people in MS itself are talking about this at all.
  • It’s an old post, but I’d read Michael Swanson’s thoughts on Presentation Model before you run off and use the pattern.

 

Three Musketeers Retirement Notice

The silly Three Musketeers thematic interludes just require more creativity than I can summon on a regular basis.  Let’s just say they stopped the evil Lady de Winter in her diabolical mission (even though she’s usually the most interesting character in the movie adaptations.  Seriously, who are you going to root for, Chris O’Donnell or Rebecca De Mornay/Faye Dunnaway?  That’s what I thought;) and delivered their very complex WinForms application on time with minimal fuss with a healthy infrastructure of automated testing.  And for the hard core Dumas fans, let’s just forget about how badly things end in the Man in the Iron Mask because it still depresses me in a way that has only been topped by “they killed Wash!.”

 

Where Next?

I’ve got to tally up the poll on this one, but for the sake of narrative continuity I’m going to wrap up Model View Presenter with some quick and easy to write posts on View/Presenter communication and dividing roles.  After that, I’m not sure yet, but the response has been so positive that I’ll definitely keep going for a while.  I will finish this by no later than mid July.  I’m shooting for 2-3 posts a week.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Build your own CAB, Design Patterns, Featured. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Alan,

    This isn’t particularly a quick question to answer, but…

    1.) This series is specific to WinForms and I wouldn’t try to apply it directly to ASP.Net. I’d recommend looking at Igloo in Castle for more on MVP with WebForms.

    2.) It is chicken and egg, but in my case the Presenter is predominant, not the View. I navigate to a Presenter object that has some sort of exposed .View {get;} property. The View, and anything else the Presenter needs, is usually pushed into the Presenter via Dependency Injection. My systems generally use StructureMap for DI.

  • Alan Avante

    Add me to the list of people who would truly appreciate the end to end code, or any reasonable facsimile of this.

    It’s an excellent series of articles, but if the gaps are not closed, it’s like building an eighth wonder of the world and not uncovering the thing so people can see it in it’s full glory.

  • Alan Avante

    I still do not see where the presenter is actually instantiated. You never show this piece of code…which, IMO, is key to bringing the whole thing together. Is the presenter instantiated in the Page_Init? Could you break down and show us ignoramuses exactly where the passive presenter is instantiated? It’s doubly confusing because you actually have a method from the presenter which tells the view of the instantiated presenter!

    This looks like a chicken and egg scenario to me dude…

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    5? There are 5?

    The Three Musketeers
    Twenty Years Later/After whatever it was
    The Man in the Iron Mask

    What else?

  • http://blog.gregdking.com Greg King

    Great series of articles, and thank you for recalling my memories of The Three Musketeers (I have read all 5 books).

  • http://www.e-Crescendo.com jdn

    Did you upload the zip anywhere?

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Cleve,

    Ugh. You’re the second person to ask. I don’t really have end to end samples, but I will upload a zip of what I’ve got tonight.

    Jeremy

  • Cleve Littlefield

    I love the series, and you have more clear made the subtle differences between these patterns.

    However, I (and I assume a lot of others as well) learn better from seeing the code end to end. Anyway you can ammend a zip file to each post to show the full code of the part? This would help a lot.Doesnt have to really work, just would let people tie the pieces together.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Steve,

    Thanks for the comment, but these posts are aimed squarely at WinForms development. It’s not entirely safe to assume that things work exactly the same in the ASP.Net/WebForms world.

    Jeremy

  • Steve

    Thanks – good post

    I’m using Billy McCafferty’s MVP setup
    (see more: http://www.codeproject.com/aspnet/NHibernateBestPractices.asp)

    It’s good to see you cover the different types and your article shed light on ways I can utilize the MVP I’m developing with.

    Thanks again

    (PS. complex screens in MVP – that is a good topic – AJAX enabled where the customer wants to see multiple data – ie. a customer, his address, etc… ) all one screen.