MVP design mode

Source: Internet
Author: User

Wikipedia

Model-view-presenter (MVP) is a user interface design pattern that is widely used for convenient automated unit testing and for improved separation of concerns in rendering logic (separation of concerns).

    • The model defines the data model that the user interface needs to be displayed, and one of the models contains the relevant business logic.
    • The view is the terminal that renders the user interface, which shows the data from Model, and the user command route after Presenter the event processing.
    • Presenter contains the event handling of the component, retrieves the Model acquisition data, and communicates with the View the data obtained through format conversion.

The MVP design pattern usually adds to the Controller's work as a back-end program for the overall application.

Baidu Encyclopedia

MVP is all called Model-view-presenter,model to provide data, view is responsible for display, Controller/presenter is responsible for the processing of logic. There is a big difference between MVP and MVC: In MVP, view does not use model directly, communication between them is done through presenter (Controller in MVC), all interactions occur inside presenter, In MVC, view reads the data directly from the model rather than through the Controller.

1 MVC and MVP

The MVP is evolved from the classic pattern MVC, where the basic ideas are interlinked: Controller/presenter is responsible for the processing of logic, model provides data, and view is responsible for the display. As a new model, there is a significant difference between MVP and MVC: In MVP, view does not use model directly, communication between them is through presenter (Controller in MVC), all interactions occur within presenter, In MVC, view reads data from the direct model rather than through the Controller.

In MVC, view is directly accessible to the model! As a result, the view contains the model information and inevitably includes some business logic. In the MVC model, more attention is paid to the constant of the model, while there are several different displays of the model, and the view. So, in the MVC model, models do not depend on view, but view is dependent on model. Not only that, because some business logic is implemented in view, it is difficult to change the view, at least those business logic is not reusable. [1]

2 solving MVC problems

In the MVP, presenter completely separates the model from the view, and the main program logic is implemented in presenter. Furthermore, presenter is not directly related to the specific view, but interacts through a well-defined interface, allowing the presenter to be kept constant when the view is changed, that is, reuse! Not only that, we can also write Test view, simulate the user's various operations, so as to achieve the test of presenter-without the need to use automated testing tools. We can even test the logic of presenter by writing a mock Object (that is, an interface that implements the model and view, but no concrete content) when the model and view are not finished. In the MVP, the logic of the application is mainly implemented in presenter, where the view is a very thin layer. As a result, a design pattern for presenter first was proposed, which was to design and develop presenter based on user story. In this process, the view is simple enough to display the information clearly. At the back, you can change the view as you want, without any effect on the presenter. If the UI to be implemented is complex, and the associated display logic is related to model, you can place a adapter between the view and the presenter. This adapter to access the model and view to avoid the association between the two. At the same time, because the adapter realizes the interface of the view, it can guarantee the same interface with the presenter. This guarantees the simplicity of the interface between the view and the presenter, without losing the flexibility of the UI. In MVP mode, view should only have a simple Set/get method, the user input and Settings interface display content, in addition to this should not have more content, never allow direct access to model--this is a big difference with MVC. [1]

3 Advantages

1, the model and the view completely separate, we can modify the view without affecting the model

2. Models can be used more efficiently because all interactions occur in one place--presenter internal

3, we can use a presenter for multiple views without changing the logic of presenter. This feature is very useful because view changes are always more frequent than models.

4. If we put logic in presenter, then we can test these logic out of the user interface (unit test) [1]

4 Disadvantages

Because view rendering is placed in presenter, views and presenter interact too frequently. It is also important to understand that if presenter renders the view too much, it often makes it more closely related to a particular view. Once the view needs to be changed, the presenter also needs to be changed. For example, the presenter used to render HTML now also needs to be used for rendering PDFs, so the view is likely to need to be changed.

Microsoft documentation

Design mode: Model View Presenter

Jean-paul Boodhoo

As UI creation techniques such as ASP. NET and Windows®form become more powerful, it is common practice for the UI layer to perform more functions. Because there is no clear delineation of responsibilities, the UI layer often becomes the universal proxy for the logical layer, which in fact belongs to the other layers of the application. Model View Presenter (MVP) mode is a design pattern specifically designed to solve this problem. To prove my point, I'll follow the MVP pattern to create a display for the customers in the Northwind database.

Why should there be too much logic in the UI layer? It is difficult to test code in the application UI layer if you do not run the application manually, or if you fail to maintain a highly advanced UI runner script that automates the UI component. This is a cumbersome matter in itself, and the bigger problem is the large number of duplicate code between normal views in the application. When you replicate the logic of performing specific business functions between different parts of the UI layer, it is often difficult to find good refactoring candidates. The MVP design pattern makes it easier to detach logic and code from the UI layer, making it easier to test reusable code.

Figure 1 shows the primary layer that makes up the sample application. Note that the UI layer and presentation layer use different packages. You might expect them to use the same package, but actually the UI layer of a project should consist of only two UI elements-forms and controls. In a Web Forms project, it is typically a collection of ASP. NET Web Forms, user controls, and server controls. In Windows Forms, a collection of Windows Forms, user controls, and third-party libraries. This additional layer is used to separate the display and logic. There can be objects in the presentation layer that actually implement UI behavior, such as validation display, collection input for the UI, and so on.

Figure 1 Application Architecture

Follow the MVP

As shown in Figure 2, the UI for this project is very standard. When the page loads, the screen displays a drop-down box populated with all the customers in the Northwind database. If you select a customer from the drop-down list, the page will be updated to display the customer's information. By following the MVP design pattern, you can detach a variety of behaviors from the UI layer and place them into your own classes. Figure 3 shows a class diagram that represents the association between the different classes involved.

Figure 2 Customer Information

It is important to note that the renderer is not aware of any knowledge of the actual UI layer of the application. It knows that it can talk to the interface, but does not know or care about the specific implementation of the interface. This has prompted the reuse of the representations between different UI technologies.

I'll use test-driven development (TDD) to create a customer screen feature. Figure 4 shows the details of the first test I will use to illustrate the behavior I expect to see on page loading. TDD allows me to focus on one problem at a time, writing only enough code that will allow the test to pass before proceeding. In this test, I will use a mock object framework called NMock2 to build an interface simulation implementation.

Figure 3 MVP Class chart

In my MVP implementation, I decided to take the representation as a subsidiary of the view it will work with. It's always nice to create objects in a state that makes them work immediately. In this application, the presentation layer actually relies on the service layer to invoke the domain functionality. Because of this requirement, it is also necessary to establish a representation with an interface, through which it can talk to the service class. This will make sure that once the renderer is established, it can do all the work it needs to do. I'll start by creating two specific simulations: one for the service layer and one for the view that the renderer will use.

Why would you create a simulation? The rule of unit testing is to isolate the test as much as possible to focus on a particular object. In this test, I only focus on the expected behavior of the renderer. At this point, I do not care about the actual implementation of the view interface or the service interface, I believe those interfaces define the protocol, and the corresponding setting simulation to behave. This ensures that I focus my tests on the representation behavior I expect, regardless of the object on which it depends. After calling its initialization method, I expect that the representation behaves as follows.

First, the renderer should call the Getcustomerlist method on the Icustomertask service-layer object (simulated in the test). Note that you can use NMock to mimic the behavior of impersonation. For the service layer, I want it to return the analog ilookupcollection to the renderer. Then, after the renderer retrieves ilookupcollection from the service layer, it should call the collection's BindTo method and pass the method to the ILookupList implementation. By using the Nmockexpect.once method, I can be sure that if the renderer does not call the method once (and only once), the test will fail.

After writing the test, I will be in a completely non-editable state. I will do the simplest job possible to make the test pass.

Make the first Test pass

One of the benefits of writing tests first is that I now have a vision that I can follow to compile and eventually pass the tests. The first test consists of two interfaces that do not yet exist. These interfaces are prerequisites for compiling code correctly. I'll start with the IViewCustomerView code:

public interface IViewCustomerView
{
ILookupList customerlist {get;}
}

This interface provides a property that returns an ILookupList interface implementation. For this issue, I do not have a ilookuplist interface, or even implement a tool. To pass this test, I don't need a clear implementation tool so I can continue to create the ILookupList interface:?

Public interface ILookupList {}

At this point, the ILookupList interface does not look useful. My goal is to compile and pass the tests, and these interfaces can meet the requirements of the test. Now it's time to turn the focus to the object I'm actually testing-viewcustomerpresenter.? This class does not yet exist, but looking back at the test, you can draw two important facts: it has a constructor that requires a view and service implementation as a dependency, and has an empty Initialize method. The code in Figure 5 shows how to compile the test.

Keep in mind that the representation requires all of its dependencies to work productively, which is why you are passing in views and services. I did not implement the initialization method, so if I run the test I will get notimplementedexception.

As mentioned above, I did not blindly write the representation code; by looking at the test, I have learned the behavior that the representation should behave after invoking the initialization method. The implementation code for the behavior is as follows:

public void Initialize ()
Task. Getcustomerlist (). BindTo (view. customerlist);
}

The source code included with this article has a complete implementation of the Getcustomerlist method in the Customertask class (which implements the Icustomertask interface). Although from the perspective of implementation and test representations, I do not need to know whether there is a work implementation. But it is this level of abstraction that makes it difficult for me to pass the test of the presentation class. The first test is now in a state that will be compiled and run. This proves that when the Initialize method on the caller is called, it interacts with its dependent objects in the way that I specified in the test, and eventually when the concrete implementations of those dependent objects are inserted into the renderer, I can be sure that the result view (ASPX page) will be populated with the list of customers.

Fill DropDownList

So far, I've mostly dealt with interfaces, throwing away the actual implementation details and concentrating on the representation. Now it's time to build some probing code that will eventually allow the renderer to populate the list on a Web page in a testable way. The key to implementing this functionality is the interaction that occurs in the BindTo method of the LookupCollection class. If you look at the implementation of the LookupCollection class in 16, you will notice that it implements the Ilookupcollection interface. The source code for this article comes with the accompanying test, which can be used to establish the functionality of the LookupCollection class.

The implementation of the BindTo method is particularly interesting. Note In this method, the collection repeats the private list of the ilookupdto implementation itself. Ilookupdto is an interface that is well bound to the UI layer's combo box:

public interface Ilookupdto
{
String Text {get;}
}

Figure 7 shows the code for testing the BindTo method of the lookup collection, which will help explain the expected interaction between LookupCollection and ILookupList. The last point is particularly interesting. In this test, I want to add an item to the list currently, LookupCollection will call the Clear method in the ILookupList implementation. Then I want to be able to raise the add 10 times in ILookupList, and as an argument to the Add method, LookupCollection will pass in the object that implements the Ilookupdto interface. To make it work with controls in a Web project, such as a drop-down list box, you need to create an ilookuplist implementation that knows how to work with controls in a Web project.

The source code included with this article contains a name MVP. Web.Controls of the project. This project contains all the Web-specific controls or classes that I chose to use to create a complete solution. Why do I put code in this project, not in the APP_CODE directory or Web project? The answer is testability. It is difficult to test any control in a WEB project directly without manually running the application or using a test program to automate the UI test. The MVP mode allows me to consider a higher level of abstraction without having to run the application manually and to test the implementation of the core interfaces (ILookupList and ilookupcollection). I'm going to add a new class to the Web.Controls project: the WebLookupList control. Figure 8 shows the first test of this class.

Some of the issues are highlighted in the tests shown in Figure 8. Obviously, the test project requires a reference to the system.web library so that it can instantiate the DropDownList Web control. To see the test further, you should understand that the WebLookupList class will implement the ILookupList interface. It also takes ListControl as a dependent object. The two most common ListControl implementations in the System.Web.UI.WebControls namespace are the DropDownList and ListBox classes. The main function of the test in Figure 8 is to ensure that weblookuplist correctly updates the status of the actual Web ListControl to the state in which it is delegating responsibility. Figure 9 shows the class diagram of the classes involved in the WebLookupList implementation. I can use the code in Figure 10 to meet the requirements for the first test of the WebLookupList control.

Figure 9 WebLookupList Class

Keep in mind that one key to MVP is the separation of layers introduced by the CREATE view interface. The renderer does not understand the specific implementation of the view, and the individual ilookuplist it wants to talk to, only that it can invoke any method defined by those interfaces. Finally, the WebLookupList class is a class that wraps and delegates to the underlying ListControl (the base class for some listcontrols defined in the System.Web.UI.WebControls project). With this code, I can compile and run the WebLookupList control test, and now the test should pass smoothly. I can add another test for weblookuplist to test the actual behavior of the Clear method:

[Test]
public void Shouldclearunderlyinglist ()
{
ListControl weblist = new DropDownList ();
ILookupList list = new WebLookupList (weblist);
WEBLIST.ITEMS.ADD (New ListItem ("1", "1"));
List. Clear ();
Assert.AreEqual (0, WebList.Items.Count);
}

In addition, I will test whether it will actually change the state of the underlying ListControl (DropDownList) when calling the method of the WebLookupList class itself. WebLookupList can now complete the functions of populating the DropDownList in Web Form. Now you can bind all the programs together to get a Web page drop-down list of populated customer lists.

Implementing the View interface

Since I am building the Web Form front end, the implementation of the IViewCustomerView interface must be a Web form or user control. For the sake of this column, I set it as a Web Form. The general appearance of the page has been created, as shown in 2. Now I just need to implement the view interface. Switching to the source code of the Viewcustomers.aspx page, I can add the following code to indicate that this page is required to implement the Iviewcustomersview interface:

public partial class Viewcustomers:P Age,iviewcustomerview

If you observe the sample code, you will find that the WEB project and Presentation are two completely different assemblies. Furthermore, the Presentation project does not refer to any Web.ui project, which further maintains the separation layer. On the other hand, the Web.ui project must reference the Presentation project, because both the view interface and the renderer are in the project.

By choosing to implement the IViewCustomerView interface, our WEB page can now implement any method or property defined by that interface. There is only one property on the current IViewCustomerView interface, which is a getter that can return any implementation of the ILookupList interface. I have added a reference to the Web.Controls project so that I can instantiate the WebLookupListControl. I do this because WebLookupListControl implements the ILookupList interface, and it knows how to delegate to the actual webcontrols in ASP. Check out the ASPX on the Viewcustomer page and you will find that the customer list is just a asp:dropdownlist control:

<td>Customers:</td>
runat= "Server" width= "308px" ></asp:DropDownList></td>
</tr>

With these existing code, I can quickly continue to implement the code required to meet the IViewCustomerView interface implementation:

Public ILookupList CustomerList
{
get {return new WebLookupList (this.customerdropdownlist);}
}

I now need to invoke the Initialize method on the renderer to trigger the method to actually perform some operations. Therefore, the view needs to be able to instantiate the renderer so that it can invoke its method. If you look back at the presentation, you'll remember that it requires the view and service to work with it. The Icustomertask interface represents an interface located at the application service layer. The service layer is typically responsible for reconciling the interactions between domain objects and translating the results of these interactions into a data Transfer Objects, DTO, and then passing it from the service layer to the presentation layer to the UI layer. But here's the problem: I've already stipulated that the representation needs to be constructed with the view and the service implementation.

The actual instantiation of the representation will be done in the source code of the Web page. This is a problem because the UI project does not reference any of the service-tier projects. However, the project is referenced by a service-tier project. You can resolve this issue by adding an overloaded constructor to Viewcustomerpresenterclass:

This (view, new Customertask ()) {}

This new constructor satisfies the implementation requirements of both the representation view and the service, while maintaining the separation of the UI layer from the service layer. Now it's easy to complete the following code for the source code:

protected override void OnInit (EventArgs e)
{
Base. OnInit (e);
Presenter = new Viewcustomerpresenter (this);
}
protected void Page_Load (object sender, EventArgs e)
if (! IsPostBack) presenter. Initialize ();
}

Note that the key to the presentation instantiation is that I will take advantage of the new constructor overload, and the Web Form will pass itself as an object implementing the View interface.

I can create and run the application immediately, using code from the implemented source codes. Now that you don't need any data-binding code from your source code, you can populate the DropDownList on your Web page with a list of customer names. In addition, test scores have been run on all the code snippets that eventually work together, which ensures that the presentation layer architecture works as expected.

Now I'm going to summarize my discussion of MVP by showing you the steps required to display the selected customer information in DropDownList. Again, I will first write a test to describe the behavior I want to observe. (see Figure 11).

As mentioned above, I will use the NMock library to create simulations of task and view interfaces. This particular test validates the behavior of the representation by requesting a DTO that represents a specific customer to the service layer. When the renderer retrieves a DTO from the service layer, it updates the properties on the view directly so that the view does not have to know anything about how to correctly display the object information. For simplicity, I will no longer discuss the implementation of the SelectedItem property on the WebLookupList control; instead, I'll leave it to you to check the source code for details about the implementation. This test really shows the interaction that occurs between the renderer and the view after the Customerdto is retrieved from the service layer. If I try to run the test now, I will face a serious failure because many of the properties on the view interface do not yet exist. Therefore, I will proceed and add the necessary members for the IViewCustomerView interface, as shown in 12.

After these interface members are added, my Web form may complain because it no longer satisfies the interface protocol, so I must return the source code of the Web form and implement the rest of the members. As described above, the entire markup for a Web page has been created, and the table cell has been marked as the "Runat=server" property and has been named according to the information it should display. This makes it very easy for the resulting code to implement the interface members:

public string CompanyName
{
set {This.companyNameLabel.InnerText = value;}
}
public string ContactName
{
set {This.contactNameLabel.InnerText = value;}
}
...

With the implementation of the setter attribute, there is only one final thing left to complete. I need a way to tell the renderer that the information for the selected customer is displayed. Looking back at the test, you will find that the implementation of this behavior is in the Displaycustomerdetails method of the renderer. However, this method does not have any parameters. When called, the renderer returns a view from which to extract any information it needs (retrieved using ILookupList), and then uses that information to retrieve the details of the selected customer. From the UI point of view, what I need to do is set the AutoPostBack property of DropDownList to True, and I need to add the following event handler hook code to the page's OnInit method:

protected override void OnInit (EventArgs e)
{
Base. OnInit (e);
Presenter = new Viewcustomerpresenter (this);
this.customerDropDownList.SelectedIndexChanged + = Delegate
{
Presenter. Displaycustomerdetails ();
};
}

This event handler ensures that when a new customer is selected in the drop-down list, the view displays the request representation for that customer's details.

It is important to note that this is typical behavior. When the view request renderer performs an action, it does not give any specific details and will be represented by the renderer to decide whether to return the view and use the view interface to get any information it needs. Figure 13 shows the code that implements the desired behavior in the renderer.

Hopefully, you can now understand the value of adding a presentation layer. The representation is responsible for attempting to retrieve the customer ID whose details need to be displayed. This is the code that is normally executed in the source code, but it is now in the class, and I can test and practice it completely outside of any presentation layer technology.

If the renderer is able to retrieve a valid customer ID from the view, it will turn to the service layer and request a DTO that represents the customer details. After the renderer obtains the DTO, it updates the view with the information contained in the DTO. The key point to note is the simplicity of the view interface, in addition to the ILookupList interface, the view interface is composed entirely of string datatypes. The final responsibility of the representation is to correctly transform and format the information retrieved from the DTO so that it can be actually passed to the view as a string. Although not explained in this example, the representation can also be responsible for reading information from the view and converting it to the necessary type that the service layer expects.

After all the code snippets are complete, I can run the application now. When I first load the page, I get a list of customers and show (unchecked) the first customer in DropDownList. If I select a customer, a postback occurs, interaction between the view and the renderer is made, and the Web page is updated with the relevant customer information.

MVP design mode

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.