今回はGUIアプリやモバイルアプリでよく使われるMVPアーキテクチャについてまとめます。
目次
MVPアーキテクチャの全体像

プロジェクトによって、Model/Presenterの責務が変わることがあるが、基本的に処理の流れ・依存関係は上記の通りだ。
家計簿アプリがあるとして、ボタンを押したらDBにアクセスして今月の出費一覧を表示する例の場合は以下の感じだ。
- まずViewは画面を組み立てる
- ボタンが押されたらViewはPresenterの出費一覧取得処理を実行する
- PresenterはModelのDBから出費情報取得処理を実行する
- PresenterはViewの出費一覧描画処理を3.の結果を渡して実行する
MVPアーキテクチャのメリット
出費一覧表示の例を見るとPresenterを介する必要ある?と思うかもしれない。
だが、ViewはModelを知らなくてもPresenterの内容さえ知っていればいいので、出費一覧をDBじゃなくて別サーバーから取得する処理に変更したい場合でもModelだけ変更するのみで済みView/Presenterは影響を受けない。
また、3層にすることで本来描画のみのクラスにDBやサーバーアクセス処理を書いて肥大化してしまうなどを防ぐ。
肥大化するとチーム開発だとコンフリクトが起きたり、この処理どこだっけ?とか、少しの修正が多くの場所に影響するみたいなことが多くなってしまう。またテストコードを書きにくかったり不具合発生時に原因特定しにくいというのも大きなデメリットだ。
描画はView、ロジックはPresenter、DB/APIアクセスはModelなどとしっかり責務が分かれているとそれぞれの層でテストコードが書きやすい。
View層
UI周りの処理をつかさどるクラス。主に画面描画周りの処理を行う。
基本的にPresenterから描画処理を呼び出される。Modelからは直接呼ばれなく、どんなModelの実装でも、Presenterさえ知っていれば良いといった感じ。
ボタンが押されたらPresenter処理を叩いて、Presenterは処理が終わった後にViewの結果表示の描画関数を実行するといった流れだ。
Presenter層
View層から依頼された処理を行う層。結果を画面に反映するためにView層の処理を呼び出す。
DBやAPIアクセスなど、Model層の処理を組み合わせて呼び出してその結果をViewの関数を呼び出して反映する。
ここにビジネスロジックなどを集約する場合もあれば、ビジネスロジックはModelや他の層に集約して、Presenterはそれらを組み立てるだけという場合もある。
View/Presenterとのやり取り

ViewとPresenterは相互に呼び合うが、実際にどう実装するか。
ViewはPresenterオブジェクトを、PresenterはViewオブジェクトをインスタンス変数として持っておく。
お互いにインスタンス変数として持っていれば相互に処理を呼び出すことが可能だ。
そして、View/Presenterのinterfaceを記載し、具体的な処理をそのinterfaceを継承して実装する。
このinterfaceをContractとかいったりするが、プロジェクトによって呼び方違ったりそもそもinterfaceがなかったりする。
Model層
この層はかなり自由度が高い。APIアクセスやDB処理を入れるのが一般的。
この層にビジネスロジックやドメイン処理集約する場合もあればPresenterがその役割で、ModelはDB/APIなどの処理のみという場合もある。
1つのアーキテクチャをベースにして独自のカスタマイズするのもあり
MVPアーキテクチャに完全に従わずに、例えばMVPにDDD的な考えも加えて、どの層からもアクセスできるDomain層を加えてそこに表示内容やドメインロジックなどを集約するなどのやり方もありだ。
アプリの規模が大きいと、Presenter/Modelが肥大化していく場合がある。Domain層を新たに加えるのは処理の集約・肥大化を防ぐことに繋がる。
基本的に層の役割を明確化・分割し、各層の依存関係も明確に定めて、その役割に従った自然な配置になっているかというのが大事だと思う。