MVPアーキテクチャ
MVPアーキテクチャはMVCから開発されています。MVPでは、Mはモデル、Vはビュー、Pはプレゼンターを表します。
- モデルはデータの取得を担当し、データのソースはネットワークまたはローカルデータベースなどです。
- Viewは、インターフェイスデータの表示とユーザーとの対話を担当します。
- プレゼンターは、モデルとビューの間のコミュニケーションブリッジであり、モデルとビューを分離し、ビジネスが実現される場所でもあります。
これら3つのレベルの関係は次のとおりです。
簡単な小さなプロセスで簡単に説明しましょう。
ユーザーがインターフェイスに触れてイベントをトリガーし、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つのプレゼンターを複数のビューに使用できます。
- モジュールの責任と明確なレベルの明らかな分割。
しかし同時に、このモデルのMVPには多くの欠点もありますが、その大きな欠点は
- コードの読みやすさが悪く、アプリケーションのメンテナンスコストが増加する
- インターフェイスファイルの数を大幅に増やす
たとえば、関数を変更する必要がある場合、最初にインターフェイスで問題のある場所を見つけ、次に実行されたメソッドで実行されたコードを表示しますが、MVP構造では、表示レイヤーはプレゼンターのみを保存しますインターフェイス、いくつかのメソッドを直接クリックすると、Presenterインターフェイスファイルでフォローアップします。この時点で複数の実装クラスがある場合、非常に面倒です。ViewでPresenterの実装クラスを見つける必要があります。これらは、MVPアーキテクチャを使用するコードのメンテナンスコストを増加させます。
もう1つの注意点は、MVPモデルでは、ViewレイヤーとPresenterレイヤーが互いの基本クラスまたはそれ自体を参照し、必要に応じて互いのメソッドを呼び出すことです。これにより2つのレイヤーを分離することもできますが、そのような分離はインターフェイスに完全に依存しているため、インターフェイスファイルの数が大幅に増加します。実際の開発の場合、すべての関数がインターフェイスを使用して定義できるほど複雑である必要はありません。インターフェイスの増加は、プログラムのメンテナンスコストを増加させます。たとえば、コードをたどるときにインターフェイスファイルをたどるのは簡単ですが、特定の関数の実装コードを見つけるのは困難です。
改善する
最初に注意することは、ビューとプレゼンターの分離の原則を維持する必要があるということです。これに基づいて、インターフェイスの定義と両者間の参照が削減される限り、維持コストを削減できます。この場合、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
- モデル
- プレゼンター
- 見る
- …
- 一般的なツール