MVPアプリケーションアーキテクチャの理解と最適化

MVPアーキテクチャ

MVPアーキテクチャはMVCから開発されています。MVPでは、Mはモデル、Vはビュー、Pはプレゼンターを表します。

  • モデルはデータの取得を担当し、データのソースはネットワークまたはローカルデータベースなどです。
  • Viewは、インターフェイスデータの表示とユーザーとの対話を担当します。
  • プレゼンターは、モデルとビューの間のコミュニケーションブリッジであり、モデルとビューを分離し、ビジネスが実現される場所でもあります。

これら3つのレベルの関係は次のとおりです。
MVPアプリケーションアーキテクチャ図

簡単な小さなプロセスで簡単に説明しましょう。
ユーザーがインターフェイスに触れてイベントをトリガーし、ViewレイヤーがPresenterレイヤーにイベントを通知し、PresenterレイヤーがModelレイヤーにイベントを処理するよう通知し、Modelレイヤーが処理後に結果をPresenterレイヤーに送信し、次にPresenterレイヤーに送信します。ビューレイヤーに通知すると、最後にビューレイヤーが変更を加えます。これは一連のプロセスです。

MVPの例

MVPをわかりやすく説明するために、MVPの例を引用します。

モデルレイヤー

モデルレイヤーは実際にはデータレイヤーです。このレイヤーは、ネットワーク、データベース、またはファイルシステムからバイナリ形式またはJSON形式でコンテンツを取得でき、データがプレゼンターレイヤーに渡されるときに、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;
     }
}

モデル

モデルは主に、データの読み取りと書き込み、JavaBeanとネイティブデータ間の変換を扱います。インターフェイスを次のように定義します。

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

プレゼンターレイヤー

この層は、関数処理のメインコードが配置されている場所です。一般的に、アプリケーションには多くの関数があり、各関数には、その関数を処理するためのプレゼンターが必要です。

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());
     }
}

プレゼンターレイヤーの場合、通常の状況では、その機能を標準化するためのインターフェイスもあります。

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

レイヤーを表示

ビューレイヤーは、ユーザーにインターフェイスを表示するために使用されます。まず、ビューレイヤーのインターフェイス仕様を使用する必要があります。

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

実装クラスは通常、Activityまたは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);
     }
}

このように、Viewレイヤーはインターフェイス上のコンテンツのみを処理します。特定のビジネスロジックでは、ViewレイヤーがPresenterインターフェイスを参照するため、Presenterメソッドを呼び出すことができます。ViewレイヤーインターフェイスはPresenterの実装でも参照されるため、ビジネスまたはコールバックでViewインターフェイスメソッドを直接呼び出して、インターフェイスを変更できます。

MVPアーキテクチャの長所と短所

MVPの利点は、上記の例から要約できます。

  1. プレゼンターに多くのビジネスコードを配置し、アクティビティの複雑さを大幅に軽減します
  2. 非表示のデータであるデータは、モデルレイヤーによって処理されます。モデルレイヤーは、ビューレイヤーに対して完全に透過的です。
  3. プレゼンターは再利用でき、1つのプレゼンターを複数のビューに使用できます。
  4. モジュールの責任と明確なレベルの明らかな分割。

しかし同時に、このモデルのMVPには多くの欠点もありますが、その大きな欠点は

  • コードの読みやすさが悪く、アプリケーションのメンテナンスコストが増加する
  • インターフェイスファイルの数を大幅に増やす

たとえば、関数を変更する必要がある場合、最初にインターフェイスで問題のある場所を見つけ、次に実行されたメソッドで実行されたコードを表示しますが、MVP構造では、表示レイヤーはプレゼンターのみを保存しますインターフェイス、いくつかのメソッドを直接クリックすると、Presenterインターフェイスファイルでフォローアップします。この時点で複数の実装クラスがある場合、非常に面倒です。ViewでPresenterの実装クラスを見つける必要があります。これらは、MVPアーキテクチャを使用するコードのメンテナンスコストを増加させます。

もう1つの注意点は、MVPモデルでは、ViewレイヤーとPresenterレイヤーが互いの基本クラスまたはそれ自体を参照し、必要に応じて互いのメソッドを呼び出すことです。これにより2つのレイヤーを分離することもできますが、そのような分離はインターフェイスに完全に依存しているため、インターフェイスファイルの数が大幅に増加します。実際の開発の場合、すべての関数がインターフェイスを使用して定義できるほど複雑である必要はありません。インターフェイスの増加は、プログラムのメンテナンスコストを増加させます。たとえば、コードをたどるときにインターフェイスファイルをたどるのは簡単ですが、特定の関数の実装コードを見つけるのは困難です。

改善する

最初に注意することは、ビューとプレゼンターの分離の原則を維持する必要があるということです。これに基づいて、インターフェイスの定義と両者間の参照が削減される限り、維持コストを削減できます。この場合、MVPアーキテクチャは次のようになります。
改善されたMVPアーキテクチャ

MVPモードの場合、Presenterの多くの機能はインターフェイスで変更をトリガーする必要があるため、Viewレイヤーインターフェイスを保持し、必要に応じてこのメソッドを呼び出します。この参照が増えるのは、まさにMVPコードの複雑さのためです。したがって、この問題を解決するには、PresenterはViewインターフェイスへの依存を放棄し、ビジネスロジックのみを完全に処理し、インターフェイスの操作から完全に分離する必要があります。

つまり、上記のMVP構造図では、ViewとPresenter間の双方向参照を一方向参照に変更する必要があります。ビューレイヤーはプレゼンターへの参照を保持し、その逆も同様です。これにより、Viewインターフェイスの定義も不要になり、Presenterがインターフェイスを使用する必要があるかどうかはコード構造に完全に依存しないため、このモードのインターフェイスファイルの数が減ります。

それだけでなく、改善後、プレゼンターはビジネスロジックに完全に集中できるようになります。そうでない場合、プレゼンターはいつどのビューのメソッドを呼び出す必要があります。抽象化されたものを使用する

改善後の問題

これを行った後、ビューへの参照がないため、インターフェイスを変更する必要があるときにインターフェイスに通知する必要があることが問題になります。これを解決するには2つの方法があります。

  • setListenerを使用して、プレゼンターでリスナーを設定します。ロジックでインターフェイスを変更する必要がある場合、リスナーのインターフェイスが呼び出されます。
  • ViewレイヤーがPresenterメソッドを呼び出すと、コールバックインターフェイスを渡して、将来発生する可能性のあるインターフェイスの変更を処理します。

上記の方法を使用すると、Viewインターフェイスを参照せずにMVPモードのすべての機能を完了できます。実際、リスナーの使用はビューインターフェイスの使用と似ていますが、この状況はより一般的であるため、プレゼンターはビューに依存せずに作業できます。

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)
     }
}

コード構造

改良されたMVPモデルを使用すると、コードは関数ベースのモデルになります。パッケージ構造には、次のソリューションを使用できます。

  • src
    • 一般的なツール
      • ネットワークベースライブラリ
      • データ解析
    • ユニバーサルUIコンポーネント
      • 一般的に使用されるカスタムビュー
      • 一般的に使用されるインターフェイスコンポーネント
    • 機能1
      • モデル
        • javabean
      • プレゼンター
      • 見る
        • アクティビティ
        • 断片
        • 見る
    • 機能2
      • モデル
      • プレゼンター
      • 見る

おすすめ

転載: blog.csdn.net/Lee_Swifter/article/details/104717081
おすすめ