はじめに
この記事は、以前の記事の続きです。
GoogleSamples(android-architecture)を斜め読みして筆者が印象に残った内容を書きます。
バックナンバー
1. Model-View-Presenter(MVP)+αを読んでみる
2. Clean Architectureを読んでみる
3. MVVM & DataBindingを読んでみる
4. MVVM & LiveDataを読んでみる
MVP - Clean Architecture
「Clean Architecture」のキモとして「UseCaseパターン」が使われています。
MVPは以前の記事と同じなので、異なる部分だけ要約します。
com.example.(...).xxx;
com.example.(...).xxx.domain;
com.example.(...).xxx.domain.model;
com.example.(...).xxx.domain.usecase;
...
domain パッケージにビジネスロジックを集約する感じ。
google samplesのユースケースは通信を主体にしたロジックの様なので、RequestValue, ResponseValueというinner classを定義しています。
汎用的に考えると、各ユースケースの in / out のベースクラスを定義して高い抽象化を実現したいのだと思います。
public abstract class UseCase<Q extends UseCase.RequestValues, P extends UseCase.ResponseValue> {
public interface RequestValues { /* 空定義 */}
public interface ResponseValue {/* 空定義 */}
public interface UseCaseCallback<R> {
void onSuccess(R response);
void onError();
}
}
ユースケースの対象となるモデルを定義し、ユースケース毎にモデルの処理を定義していきます。
サンプルコードでは、モデルを「Task(やるべき作業)」として、ユースケースは「Get, Add, Complete」等としています。
Task + Get = GetTask → タスクを取得する
Task + Add = AddTask → タスクを追加する
Task + Complete = CompleteTask → タスクが完了した
分かりやすいですね。
車なら「モデル:Car、ユースケース:Ignite(エンジン点火)、Run(走る)、Idling(アイドリング)、Fueling(給油)」
人なら「モデル:Person、ユースケース:Sleep(寝る)、Eat(食べる)、Work(働く)、Vacation(休暇)」
プログラムとしては、以下の構造になっています。分かりやすいよう、独自のコードで表現します。
package com.example.(...).xxx.model;
public class Car {}
package com.example.(...).xxx.usecase;
public class IgniteCar extends UseCase<IgniteCar.InputValues, IgniteCar.OutputValue> {
public static final class InputValues implements UseCase.InputValues {...}
public static final class OutputValue implements UseCase.OutputValue {...}
}
いかがでしたでしょうか
UseCaseパターンはビジネスとの親和性が高く、ビジネスの良し悪しがパッケージ / クラス構成の良し悪しに出てきそうですね。
(ソースや設計がイケてない → ビジネスモデルがイケてない!?)