はじめに
最近いろんなところでMVPに関する記事や勉強会を目にします。
私もプライベートなプロジェクトを作ってMVPを使った設計を行なっていますが、
実際に業務でMVPを取り入れていくために必要であろう導入部分を書こうと思います。
※ここでのMVPアーキテクチャの前提はAndroid-CleanArchitectureかkonifarさん推奨のアーキテクチャを前提にしています。
つまるところMVPの導入ではUseCaseの部分がハードルになると思います。
##MVPとは
大きく Model View Presenter で構成されるアーキテクチャ
http://konifar.hatenablog.com/entry/2015/04/17/010606
↑詳しい内容はKonifarさんのこの記事なんかがわかりやすくて良いです。
ここでは具体的に導入していくことに着眼して話を進めていきます。
Model層
Model部分は主に下記のような構成になります。
Repository Entity などのデータ直接操作や格納を行う部分
ApiやDB通信部分自体を行う部分
- Repository
- Entity
- Api
- DB
View層
言わずと知れたViewコンポーネント系
Presenter層
ControllerであるFragmentやActivityに対して、
Model層からデータを取得してViewに反映させる部分を分離します。
ControllerはViewの種類ごとに作られたPresenterと呼ばれるものを使って
データをViewに反映していきます。
表示したいViewとデータタイプはたいていの場合固定ですが、場合によっては
データの取得方法はDBだったりAPIだったりEndpointが様々だったりします。
その固定なView反映部分をPresenterで負担し、通信手段等場合によって変わりうる部分は
冗長化できるようにUseCaseと呼ばれるInterfaceを使って切り出したりします。
- Presenter
- UseCase
MVPの導入で難しい部分
PresenterとUseCaseの部分が導入コストがかかります。
順番的にはPresenter → UseCaseの順で導入していくのが
ステップとして影響範囲も絞りながら進められます。
Presenterの導入
Presenterは比較的簡単に導入できます。
View単位でPresenterをどんどん作っていきそのViewを操作している処理の部分を
Presenter内部に委譲していきます。
最終的に下記のようになるイメージですが実際にやる場合は
一旦UseCaseの部分はあまり考えずにただ委譲してみます。
public class MyPresenter implements Presenter {
// Presenterはメンバにcontextやviewとともにusecaseを持ちます
private final MyView myView;
private final LoadDataUseCase loadDataUseCase;
public MyPresenter(MyView myView, LoadDataUseCase loadDataUseCase) {
this.myView = myView;
this.loadDataUseCase = loadDataUseCase;
}
public loadData() {
// 通信や具体的なデータ取得のロジックはUseCaseをimplementsしたクラスに任せます。
loadDataUseCase.execute(new CallBack() {
@override
onLoadCompleted(MyData data) {
// データ取得結果をViewにセットするのはPresenterが負担します
showData(data);
}
}
}
public showData(MyData data) {
MyView.setData(data);
}
// 以下 親Presenterのメンバ
@override
public resume() {
}
@override
public pause() {
}
@override
public destroy() {
}
}
UseCaseの導入
UseCaseの導入はデータ取得(ビジネスロジック)部分と結果受信View反映部分の
分離に等しいかなというのが雑感です。
なのでPresenterを実装する前に通信部分などをinterfaceを使って"実行"と"Callback後"に
あらかじめ分離しておくのがPresenter → UseCaseの順に改修を進める上で進めやすいかなと思います。
最終的にこのinterfaceで切り出しておいた部分がそのままUseCaseになっていくイメージです。
Presenterの部分で例を挙げたコードのloadData()でいうと
たとえばFragmentなどのControllerで通信と描画などをしてしまっている場合、
↓まずあらかじめこうなているとそのままUseCaseにできます。
// 一旦fragment内をinterfaceで整理しておく
public loadData() {
// 馴染みのあるinterfaceで切り出しておく
loadDataInterface.execute(new CallBack() {
@override
onLoadCompleted(MyData data) {
// データ取得結果をViewにセットするのはPresenterが負担します
showData(data);
}
}
}
↑こうしておけばPresenterにこれが移動した時にinterface化してある部分をそのままUseCaseにできます。
まとめ
実務上ではリファクタしようと思ったり新しいアーキテクチャを導入しようと思っても、
影響範囲や工数やスケジュールの関係でいきなり全部揃わないと壊れてしまう改修はできません。
MVPに関しても無理なく順番にプロジェクトに導入できる方法が重要です。