1. KEN0331

    Posted

    KEN0331
Changes in title
+【MVPの導入】UseCaseがむずいならまずInterfaceを使って共通化する話
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,143 @@
+## はじめに
+最近いろんなところでMVPに関する記事や勉強会を目にします。
+
+私もプライベートなプロジェクトを作ってMVPを使った設計を行なっていますが、
+実際に業務でMVPを取り入れていくために必要であろう導入部分を書こうと思います。
+
+つまるところ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 Context context;
+ private MyView myView;
+ private LoadDataUseCase loadDataUseCase;
+
+ public MyPresenter(Context context, MyView myView, LoadDataUseCase loadDataUseCase) {
+ this.context = context;
+ 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に関しても無理なく順番にプロジェクトに導入できる方法が重要です。