THE INSANE JAVA

曾每日與 Java 搏鬥的 .NET Programmer 日誌

Some Thoughts on Model View Presenter

leave a comment »

I’ve been using Passive View favor of Model View Presenter (MVP) pattern for a while and satisfy with the flexibility and testability it gives me. Until recently I smelled a rat when started building a fairly complex winform. Something missing, not addressed by others before with this pattern. The view interface looks like this:

public interface IProductView
{
        string ProductName { get; set; }
        Color ProductNameBackColor { get; set; }
        bool ProductNameVisible { get; set; }
        ......
}

It’s clear that data-centric properties (ProductName) and appearance-centric properties (ProductNameBackColor, ProductNameVisbile) are all mingled in the same interface. It’s okay if the view is relatively simple, when comes to a complex one, it can turn terribly ugly. After googling for a while, I found that most tutorials and articles I came across on MVP shared the same characteristic, the view interface is completely data-centric, like the one below:

public interface IProductView
{
        string ProductId { get; set; }
        string ProductName { get; set; }
        double Price { get; set; }
        bool IsOnSale { get; set; }
}

Most people just neglected the appearance-centric properties. Although a view abstracts a form, to me, it still represents a “visual element”, which has colors and visibility. How is the presenter supposed to access and change non-data centric UI properties? This is really a dilemma to me. In order to let the presenter controls view logics, UI properties have to be exposed via view interface somehow. One approach is to abstract all controls like this:

public interface IProductView
{
        ITextEdit ProductId { get; set; }
        ITextEdit ProductName { get; set; }
        INumericEdit Price { get; set; }
        IBooleanEdit IsOnSale { get; set; }
}

public interface ITextEdit
{
        string Text { get; set; }
        Color BackColor { get; set; }
        Color ForeColor { get; set; }
        bool Enabled { get; set; }
        bool Visible { get; set; }
}
......

In this case I can stub all controls and put expectation on them in unit test, also the view interface looks much cleaner. I struggled (and still struggling at the time I am writing this) not to do this, for one thing it creates unnecessary complexity (forces me to create custom wrapper classes for common windowsforms controls and implement the custom interface), for the other reason, initializing test cases becomes clumsy as all ITextEdit, INumericEdit require a stub. For instance, to test whether a particular view property has been set or not, currently I can do something like

Expect.Call(view.ProductName = "Product ABC");

But with this extra layer of abstraction, I have to write 2 more lines of code

ITextEdit productNameEdit = mocks.Stub<ITextEdit>();
Expect.Call(view.ProductName).Return(productNameEdit);
Expect.Call(productNameEdit = "Product ABC");

I dug through all the MVP materials again trying to find some insight, one suggested that a twisted MVP will do, but the introduction of an extra controller is somewhat confusing and hard to scope. I am yet to figure out the best approach to address this problem. :(

References

Martin Fowler’s GUI Architecture Essay (authoritative speak of GUI patterns and many others, although he refused to admit)
Rich Newman’s MVP, MVC comparison (plus introduction to Smart Client Software Factory)
Derek Greer’s MVP, MVC and PAC comparison

Written by Sean

三月 24, 2008 at 12:38 am

Leave a Reply