Understanding and optimization of MVP application architecture

MVP architecture

The MVP architecture is developed from MVC. In MVP, M stands for Model, V stands for View, and P stands for Presenter.

  • Model is responsible for obtaining data, the source of data can be network or local database, etc.;
  • View is responsible for displaying interface data and interacting with users;
  • Presenter is the communication bridge between Model and View. It separates Model and View and is also the place where business is realized;

The relationship between these three levels is as follows:
MVP application architecture diagram

Let's briefly use a simple small process to explain: the
user touches the interface to trigger an event, the View layer notifies the Presenter layer of the event, the Presenter layer notifies the Model layer to process the event, the Model layer sends the result to the Presenter layer after processing, and then the Presenter layer. Notify the View layer, and finally the View layer makes changes. This is a whole set of processes.

MVP example

In order to better illustrate the MVP, we simply cite an MVP example.

Model layer

The Model layer is actually the data layer. This layer can get some content in binary or JSON format from the network, database or file system, and when the data is passed to the Presenter layer, it should be parsed into JavaBeans.

JavaBean
public class UserBean {
     private String mFirstName;
     private String mLastName;
     public UserBean(String firstName, String lastName) {
            this. mFirstName = firstName;
            this. mLastName = lastName;
     }
     public String getFirstName() {
            return mFirstName;
     }
     public String getLastName() {
            return mLastName;
     }
}

Model

Model mainly deals with data reading and writing, conversion between JavaBean and native data. Define the interface as follows:

public interface IUserModel {
    void setID(int id);
    void setFirstName(String firstName);
    void setLastName(String lastName);
    int getID();
    UserBean load(int id);		// 通过id读取user信息,返回一个UserBean
}

Presenter layer

This layer is where the main code for function processing is located. Generally speaking, there are many functions in an application, and each function should have a Presenter to handle its functions.

public class UserPresenter {
     private IUserView mUserView;			//注意此处对 View 层的引用
     private IUserModel mUserModel;			//对 Model 层的引用

     public UserPresenter(IUserView view) {
            mUserView = view;
            mUserModel = new UserModel();
     }

     public void saveUser( int id, String firstName, String lastName) {
            mUserModel.setID(id);
            mUserModel.setFirstName(firstName);
            mUserModel.setLastName(lastName);
     }

     public void loadUser( int id) {
           UserBean user = mUserModel.load(id);
            mUserView.setFirstName(user.getFirstName()); // 通过调用IUserView的方法来更新显示
            mUserView.setLastName(user.getLastName());
     }
}

For the Presenter layer, under normal circumstances there will also be interfaces to standardize its functions.

public interface UserPresenterI {
     public void saveUser( int id, String firstName, String lastName)
     public void loadUser( int id) 
}

View layer

The View layer is used to display the interface to the user. First of all, we must use the interface specification for the View layer:

public interface IUserView {
     int getID();
     String getFristName();
     String getLastName();
     void setFirstName(String firstName);
     void setLastName(String lastName);
}

The implementation class is generally Activity or Fragment:

public class MainActivity extends Activity implements OnClickListener,IUserView {

     UserPresenterI presenter;
     EditText id,first,last;
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout. activity_main);

            findViewById(R.id. save).setOnClickListener( this);
            findViewById(R.id. load).setOnClickListener( this);
            id = (EditText) findViewById(R.id. id);
            first = (EditText) findViewById(R.id. first);
            last = (EditText) findViewById(R.id. last);

            presenter = new UserPresenter(this);		//注意此处对 Presenter 的引用
     }

     @Override
     public void onClick(View v) {
            switch (v.getId()) {
            case R.id. save:
                 presenter.saveUser(getID(), getFristName(), getLastName());
                 break;
            case R.id. load:
                 presenter.loadUser(getID());
                 break;
            default:
                 break;
           }
     }

     @Override
     public int getID() {
            return new Integer( id.getText().toString());
     }

     @Override
     public String getFristName() {
            return first.getText().toString();
     }

     @Override
     public String getLastName() {
            return last.getText().toString();
     }

     @Override
     public void setFirstName(String firstName) {
            first.setText(firstName);
     }

     @Override
     public void setLastName(String lastName) {
            last.setText(lastName);
     }
}

In this way, the View layer only processes the content on the interface. For specific business logic, because the View layer references the Presenter interface, the Presenter method can be called. The View layer interface is also referenced in the implementation of Presenter, so the View interface method can be directly called in business or callback to change the interface.

Advantages and disadvantages of MVP architecture

The advantages of MVP can be summarized from the above example:

  1. Put a lot of business code in Presenter, greatly reducing the complexity of Activity
  2. Hidden data, the data is processed by the Model layer, which is completely transparent to the View layer;
  3. Presenter can be reused, and one Presenter can be used for multiple Views.
  4. Obvious division of module responsibilities and clear levels;

But at the same time, this model of MVP will also bring many shortcomings, of which the big one is

  • Code readability is poor, increasing application maintenance costs
  • Greatly increase the number of interface files

For example, when I need to modify a function, I first find the problem location on the interface, and then view the executed code in the executed method, but in the MVP structure, the View layer only saves the Presenter Interface, if you click on some methods directly, then you will follow up in the Presenter interface file. If there are several implementation classes at this time, it will be very troublesome. You must find the implementation class of Presenter in View. These will increase the maintenance cost of the code using the MVP architecture.

Another thing to note is that in the MVP model, the View and Presenter layers refer to each other's base class or itself, and they will call each other's methods when necessary. Although this can also isolate the two layers, such isolation is completely dependent on the interface, which will greatly increase the number of interface files. In the case of real development, not every function needs to be complicated enough to be defined using an interface. The increase in interfaces will increase the maintenance cost of the program. For example, it is easy to follow the interface file when following the code, but it is difficult to find the implementation code of the specific function.

Improve

The first thing to note is that the principle of separation of View and Presenter must be maintained, and on this basis, as long as the definition of the interface and the references between both parties are reduced, the maintenance cost can be reduced. In this case, the MVP architecture will become like this:
Improved MVP architecture

For the MVP mode, because many functions of Presenter need to trigger changes on the interface, it holds a View layer interface, and this method is called when necessary. It is precisely because of the complexity of the MVP code that this reference increases. Therefore, to solve this problem, Presenter must abandon its dependence on the View interface, making it completely only deal with business logic, and completely separate from the operations on the interface.

That is to say, in the above MVP structure diagram, the bidirectional reference between View and Presenter needs to be changed to one-way reference. The View layer holds a reference to the Presenter, and vice versa. This also makes the View interface definition unnecessary, and whether Presenter needs to use the interface is completely independent of the code structure, so this will reduce the number of interface files in this mode.

Not only that, after the improvement, it also enables Presenter to fully focus on the business logic, otherwise Presenter needs to call what method of View. Use abstracted

Problem after improvement

After doing this, since there is no reference to the View, it becomes a problem that the interface should be notified when the interface needs to be changed. There are two ways to solve it:

  • Use setListener to set up the listener in the Presenter. When the logic needs the interface to change, the interface in the Listener will be called
  • When the View layer calls the Presenter method, it passes in a callback interface to handle possible future interface changes.
Example

After using the above method, all functions of the MVP mode can be completed without referencing the View interface. In fact, using Listener is similar to using the View interface, but this situation will be more general, so that Presenter can work without relying on View:

public class UserPresenter {

     private XListener listener;
     private IUserModel mUserModel;			//对 Model 层的引用

     public UserPresenter(IUserView view) {
            mUserView = view;
            mUserModel = new UserModel();
     }

     public void saveUser( int id, String firstName, String lastName) {
            mUserModel.setID(id);
            mUserModel.setFirstName(firstName);
            mUserModel.setLastName(lastName);
     }

     public void loadUser( int id) {
            UserBean user = mUserModel.load(id);
            listener.onUserGot(user);		//使用 Listener 来替代 IView
     }

    public void loadUser(int id, XListener onLoadListener) {
            UserBean user = mUserModel.load(id);
            onLoadListener.onUserGot(user);		//使用方法上的实参来替代 IView
    }

     public interface XListener {
     	   void onUserGot(User user)
     }
}

Code structure

After using the improved MVP model, the code will become a function-based model. For the package structure, the following solutions can be used:

  • src
    • General tools
      • Network base library
      • data analysis
    • Universal UI components
      • Commonly used custom View
      • Commonly used interface components
    • Function One
      • model
        • javabean
      • presenter
      • view
        • activity
        • fragment
        • view
    • Function two
      • model
      • presenter
      • view

Guess you like

Origin blog.csdn.net/Lee_Swifter/article/details/104717081