Android Architecture Blueprintsでクラス図を描きながらMVPを学ぶ


# Android Architecture BlueprintsでMVPを学ぶ
## 初めに
Androidのアーキテクチャについて学びたいと思っていた時に、調べたところ「Android Architecture Blueprints」が良いとあったので、クラス図を書きながらアーキテクチャについて学んでみます。

プロジェクト見てもいまいちつかめない方は、[PEAKS（ピークス）｜Android アプリ設計パターン入門](https://peaks.cc/books/architecture_patterns)を見るとより分かりやすいと思います。
MVPとMVVMについて解説があります。
Android開発が初めての方にはおすすめです。

## Android Architecture Blueprintsとは
Googleが公開しているAndroidアプリ（TODOアプリ）を様々なアーキテクチャで実装したプロジェクト。
アーキテクチャごとにブランチが異なり、MVPやMVVM、Clearn Architectureなど同じTODOアプリが別のアーキテクチャで書かれていて比較したら面白いです。
詳しくは、GitHubのページへ↓
[android/architecture-samples: A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.](https://github.com/android/architecture-samples)  

今回は、「Android Architecture Blueprints」では基本となるアーキテクチャとして書かれているMVPについて学んでみます。
[todo-mvp-kotlin](https://github.com/android/architecture-samples/tree/todo-mvp-kotlin)ブランチを見ていきます。

## MVPとは
まず、MVPとはを簡単に説明してみます。
MVPとは、「Model–View–Presenter」を表しています。
私の中では、ざっくりと以下のようなイメージです。

__Model__
データ構造やデータを加工する役割。

__View__
画面の表示を行う役割。
Modelで定義したデータを使って画面の表示を行い、ユーザーのイベントをPresenterへ伝える。

__Presenter__
画面と加工されたデータModelをひも付ける役割。
Viewで使う画面表示以外の処理とModelからのデータ取得を行うことで、Viewは画面表示だけを行うようにする。

MVCと似ていますが、「ModelとViewの関連をより疎にしたもの」がMVPです。
MVPでは、ModelはViewを知らないですしViewはModelを知らないです。
詳しくは、[Webアプリケーション開発者から見た、MVCとMVP、そしてMVVMの違い - Qiita](https://qiita.com/shinkuFencer/items/f2651073fb71416b6cd7#mvpmodelviewpresenter)を是非、参照してください。

## 「Android Architecture Blueprints」のMVPを見てみる
Googleが公開しているTODOアプリの構成は、以下のように示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245399/09aebdeb-c1d6-c607-b362-ce8e02030b75.png)
[android/architecture-samples at todo-mvp](https://github.com/android/architecture-samples/tree/todo-mvp)より  

REPOSITORYやLocal data dourceなどは、Modelにあたると考えます。

### クラス図

クラス図を書いてみました。

![googole-mvp-sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245399/accd7cff-38ed-0693-a9b0-b87e4337a9aa.png)

メソッド・フィールドは割愛しているところも多々あります。
関連や多重度など間違いがありましたらコメントください。
（内部定義されたインターフェースやクラスの書き方が自信ないです。）

__Model__
dataパッケージに含まれるクラスを指す。
データ構造の定義やデータを加工している。

__View__
addedittaskパッケージなどで定義されているActivityやFragmentを指す。
Presenterを持っており、Presenterから取得したデータを表示したり（具体的にはPresenterがModelから取得したデータをViewへ橋渡ししている）、データ保存などユーザーのイベントをPresenterに伝える。
因みにここでは、ViewのPresenterのセットはPresenterが生成されたタイミングでPresenter自身で行っている。

__Presenter__
addedittaskパッケージなどで定義されているPresenterを指す。
Presenterが生成された時、ModelやViewを保持する。
そうすることで、Viewからユーザーのイベントが伝えられた時、Modelを使ってデータの処理を行える。
ここでは、ViewとPresenterとの間やり取りをインターフェースで定義したContentと呼ばれるインターフェースを使っている。Presenterが持つViewの実態は、Contentで定義されたViewのインターフェースであるため、必要以上にViewの処理にアクセスできないようになっている。

下記は、自身が読み進めていく中で各パッケージでどのクラスが何をしているかざっくり記載しました。

#### dataパッケージについて

Roomを使ってSQLiteによるデータの保存を行っています。
Roomは、[Android Architecture Component](https://developer.android.com/topic/libraries/architecture/index.html)というテストとメンテナンスが簡単なアプリの設計を支援するライブラリの1つです。

Task
Entityクラス。
今回データ取得の対象となるtasksテーブルに対応している。

TasksRepository
DBから取得したデータソースとキャッシュ上で扱うためのTaskクラスを相互に変換して、データを取得したりDBを更新する。

TasksDataSource
タスクデータにアクセスするためのメインのエントリーポイント。

TasksLocalDataSource
DBを使った操作を行う実装クラス。
companion objectで宣言されたメソッドを使ってインスタンスを取得することでシングルトンクラスにしている。

TasksDao
Roomを使ってDBへアクセスするときに使うデータアクセス用のオブジェクト。
Queryなどが定義されている。

ToDoDatabase
Roomを使ってDBへアクセスするためのDBの定義。
RoomDatabaseを継承していることでRoomを使ってDBを扱えるようにしている。

TasksRemoteDataSource
リモート通信によるデータの操作を行う実装クラス。
object宣言をしてシングルトンクラスにしている。
ここでは、あくまでシュミレート用になっている。

ToDoDatabaseやTasksRepository、TasksLocalDataSource、TasksDaoのインスタンス生成は、mockパッケージにあるInjectionクラスが行っている。
テストするときにTasksDataSourceクラスのモックが挿入しやすいようになっているようだ。

#### addedittaskパッケージについて
他のパッケージでも同じ構成になっています。

AddEditTaskContract
ViewとPresenterとの間のやり取りを定義している。
インターフェースViewをView(ここでは、Fragment）が実装する。
インターフェースViewで定義されているメソッドは、Presenterから呼ばれるため、PresenterがViewのオブジェクトを持っている。
インターフェースPresenterをPresenterクラスが実装する。
インターフェースPresenterで定義されているメソッドは、ActivityやFragmentから呼ばれるため、ActivityやFragmentがPresenterのオブジェクトを持っている。

AddEditTaskPresenter
ユーザーからの操作に合わせて、必要に応じてデータを取得したりUIの表示を更新したりする。
PresenterがあるおかげでActivityやFragmentにロジックがほどんど含まれずにすっきりする。
ViewがもつPresenterのインスタンスは、このクラスのinitでセットする。
Repositryの実行結果は、コールバック関数によって受け取る。こうして非同期処理を実現している。

#### utilパッケージについて

SimpleCountingIdlingResource
アイドリングの仕組みを提供する。
テストの時のみ使用される。
中身はただのカウンターになっていてカウントが0の時はアイドル状態として扱う。
AtomicIntegerクラスがマルチスレッドでintを扱うクラスになっていて、これによりマルチスレッドでもカウンターとして機能するようになっている。

EspressoIdlingResource
SimpleCountingIdlingResourceクラスのインスタンスを1つにするシングルトンクラス。
Presenterクラスのデータをロードする処理メソッドなど（TasksPresenter.loadTasksメソッドなど）に使われている。

DiskIOThreadExecutor
バックグラウンドスレッドでタスクを実行するためのExecutor。

AppExecutors
アプリ全体のスレッドプールを利用した並列処理実行をする。
TasksLocalDataSource.getTasksメソッドなどDBアクセスをする重たい処理に対して並行処理をするために使われている。

## まとめ
MVPは、「ModelとViewの関連をより疎にしたもの」です。
プロジェクトを見ると、ActivityやFragmentはデータのTaskクラスがどんなものか、どのようにDBに保存しているかは全く知らないことが分かります。
ViewがPresenterのオブジェクトを持っていることで、ユーザーの操作について情報を伝え、
PresenterがViewのオブジェクトを持っていることで、UIの更新が可能になっています。
また、PresenterがTasksDataSourceのオブジェクトを持っていることで、DBとのアクセスしてデータの処理を行うことが可能になっています。
Presenterに処理が集まる比較的シンプルな設計になってます。ただ、Presenterがかなり重くなりそうです。

## 参考
[Androidアーキテクチャことはじめ ― 選定する意味と、MVP、Clean Architecture、MVVM、Fluxの特徴を理解する - エンジニアHub｜若手Webエンジニアのキャリアを考える！](https://employment.en-japan.com/engineerhub/entry/2018/01/17/110000?amp=1)  
[Android Architecture Blueprintsで学んだアプリ実装(MVP) - Qiita](https://qiita.com/HunterPigeon52/items/427417785563480cbc83)