开发者

Model View Presenter - how to implement complex Properties in an IView interace

I am finding it difficult understanding how best to implement 'IView' interface properties which are not simple types, and was wondering how others approach this in a Model View Presenter application.

The articles i've read are really good but none of them seem to approach more complex Views where you have List<> properties which are of an interface type which represent a class in your domain model, i.e. IPerson, or IName etc.

I will try to outline a scenario as briefly as i possibly can.

Presume i have a requirement for a View to ultimately persist a list of names, each consisting of 3 properties 'Forename', 'Surname', and 'Title'.

Typically i will have a domain model with a class called 'Name' with the 3 properties. This domain model will implement an Interface (in a separate 'Interfaces' class Library) called 'IName'.

Now in the 'Views' namespace in my 'Interaces' library i have an interface called 'IViewNames'. This is the view interface which any view which wants to ultimately persist the list of names will implement.

How to define this 'IViewNames' interface puzzles me. If i give it a property like so:

public List<IName> Names {get;set;}

then my implementing concrete view will ultimately have a complex property 'Names' which will need a 'getter' which loops through the fields on the View, somehow instantiate an instance of 'IName', set its properties, add to a List, before returning the List. The 'setter' will be just as complex, receiving a list of 'INames' and iterating through them setting fields on the View.

I feel like this is breaking one of the major goals of the MVP approach, which is being able to thoroughly test the application code without any concrete View implemntations. After all, i could easily write a presenter which looks at the 'View.Names' property and sends it on to a Service Layer, or set the 'View.Names' property when receiving a list of 'Name' objects back from the Service Layer. I could easily write a lot of tests which ensure everything works, everything except from that COMPLEX property in the View.

So my question is, how do others approach IView properties which are not simple types, but are in fact types of your domain model? (well types of interfaces which represent your domain model, as i clearly dont want a reference from my Presentation Layer to my Domain Model layer).

I'm more than certain there is a known technique to achieving this in an elegant way, which adheres to the Model View Presenter goals, more than my example approach does.

Than开发者_如何学运维ks in advance for any help people.


I have not worked much on the MVP design pattern but will surely try my hands on it.

Approach1 : DataBinding

In this case you can also create individual properties in IView and bind these properties in presenter to the model properties. This way, your view will not get complicated. The experience is fast and seamless as the values from UI can be directly used in model. Changing the property value in model will reflect in UI immedietly. You may have to use NotifyPropertyChange events for this.

Approach 2 : Complex Types

You can try creating List or Tuples to store these values and use the values in the presenter. You may have to use events or actions to reflect the value from model to view and vice versa.

Please let me know if it helped you. Thanks.


I have lifted this explanation from one of the articles I am writing on my website

Presenter to View Communication

There are two styles utilised for populating the View with data from the Presenter and Model that I have used. The only difference between them is how tightly coupled you mind your View being to the Model. For the example of this, we will have the following as our Model:

public class Person
{
    public int ID { get; private set; }
    public int Age { get; set; }
    public String FirstName { get; set; }
    public String LastName { get; set; }
    Public Genders Gender { get; set; }
}

Method 1: Using the Model

Now our View code:

public interface IEmployeesView
{
    void ClearList();
    void PopulateList(IEnumerable<Person> people);
}

And finally the Presenter:

public class IEmployeesPresenter
{
    public void Display()
    {
        _view.ClearList();
        _view.PopulateList(_model.AllEmployees);
    }
}

This method of population produces a link between the Model and the View; the Person object used as a parameter in PopulateList.

The advantage of this is that the concrete implementation of the IEmployeesView can decide on what to display in its list of people, picking from any or all of the properties on the Person.

Their are two disadvantages of this method. The first is that there is nothing stopping the View from calling methods on the Person, which makes it easy for lazy code to slip in. The second is that if the model were to change from a List<Person> to a List<Dog> for instance, not only would the Model and the Presenter need to change, but so the View would too.

Method 2: Using Generic Types

The other method population relies on using Tuple<...>, KeyValuePair<,> and custom classes and structs:

Now our View code:

public interface IEmployeesView
{
    void ClearList();
    void PopulateList(IEnumerable<Tuple<int, String> names);
}

And finally the Presenter:

public class IEmployeesPresenter
{
    public void Display()
    {
        var names = _model.AllEmployees.Select(x => new Tuple<int, String>(x.ID, x.FirstName + " " + x.LastName));

        _view.ClearList();
        _view.PopulateList(names);
    }
}

The advantages of this method of population is that the Model is free to change without needing to update the View, and the View has no decisions to make on what to display. It also prevents the View from calling any extra methods on the Person, as it does not have a reference to it.

The down sides to this method, are that you loose strong typing, and discoverability - It is quite obvious what a Person is but what a Tuple<int, String> is less obvious.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜