Skip to content
This repository has been archived by the owner on Dec 6, 2021. It is now read-only.

Layer_Definition ja

Tetsuya Mori edited this page Sep 11, 2018 · 4 revisions

レイヤー定義

CAFU では Clean Architecture のルールに基づいて以下のレイヤーを定義しています。

  • Domain
    • Entity
    • Structure
    • UseCase
    • Translator
  • Presentation
    • Presenter
    • View
  • Data
    • Repository
    • DataStore
  • Other
    • Resolver

クラス図として表現すると以下のようになります。

basic

Entity や Structure や Translator の関係は以下のようになります。

entity, structure and translator

Domain > Entity

アプリケーションのコアとなるデータ構造単一の責任に対する振る舞い を持つためのレイヤーです。

アクターと責務の単位でクラスが分割されることを前提として、状態や振る舞いをこのレイヤーに定義します。

原則として、Entity レイヤーのインスタンスは他のレイヤー間を行き来せず、唯一 UseCase からのみ参照されることが求められます。
本来は、Entity のインスタンスを View が直接触るべきでは無いのですが、ココを厳密にやってしまうと Presenter のメソッド数がもの凄く膨大になってしまうので、筆者としては許容範囲であると考えます。

責務

  • アクター・責務に閉じた 状態振る舞い を定義・実装する
  • UseCase の処理結果を保持するためのプロパティを提供する

関心

なし。

Domain > Structure

アプリケーション外部のデータ (Data Entity) を構造化して管理 したり 描画に作用するデータ (Presentation Entity) を取り扱う ためのレイヤーです。

ローカルストレージ・Web API・オブジェクトストレージ・mBaaS データベースなど、あらゆる外部データが提供するデータをこのレイヤーに格納します。
Structure レイヤーは外部データを保持する外部サービスとの直接的なインタフェースではありません。
あくまで、外部データの構造を表現するだけであり、外部システムとの対話は後述の DataStore レイヤーが担当します。

また、描画に必要となる情報を適切な粒度でこのレイヤーに格納します。
更に、プロパティとして値の変更を通知するストリーム(ReactiveProperty など)を持った Structure を Presenter を通じて View が受け取れば、結合を疎に保ったまま UseCase による更新を View 側で受け取ることができます。

なお、単一責任の原則に従って描画に作用するデータとゲーム外部のデータを 分離して定義する ことが強く求められます。
勿論、同一のデータを用いてやり取りすることは可能なのですが、例えば外部仕様が変化した時に描画仕様に関わるロジックも修正する必要が出てしまうため、変更汚染を Translator レイヤーで食い止められるように分けて定義するコトが望ましいと言えます。

責務

  • 外部システムが取り扱うデータを構造化して管理する
  • View で変更を監視するための IObservable を提供する
    • ReactiveProperty が便利

関心

なし。

Domain > UseCase

ビジネスロジックを記述する ためのレイヤーです。

Presenter を経由して送られてくる View からのイベントに対して、アプリケーションの要件に従った計算処理を行い、状態として保持している Entity を操作します。
また、Repository から受け取った Structure を Translator を通して変換したうえで Presenter に対してデータを渡す役割も担います。
更に、外部システムに保存すべきデータなどを Repository を通して送る役割も担います。
プロダクトの根幹となる実装を行う箇所であり、単一責任の原則にしたがってクラス自体に与える責務を適切に絞ることが肝要となります。

注意すべき点として、 Presentation レイヤーと Data レイヤーとで Structure を受け渡しする場合には Translator を通した変換処理を怠らないようにします。

責務

  • Presenter から送られてくるイベントにより、必要となる計算を行う
    • 例: 30秒のカウントダウンタイマーを開始するという呼び出しに対して時間管理 Entity を初期値30秒で初期化し毎フレームの差分秒数を減算していく
  • 初期化処理などにより View レイヤーで用いるための Structure などを構築し通知するストリームや Entity などを返す
    • 例: カウントダウンタイマーの秒数を通知するための ReactiveProperty を持った Structure のインスタンスを返す
  • 外部システムに対してデータの処理を行う際に、適切な Repository に対して命令を行う

関心

  • Entity
    • View で用いるために処理結果を反映する
  • Translator
    • 例: Repository から取得した Data Structure を Presentation Structure 変換用の Translator に渡し、戻り値を Repository に渡す
    • 例: Presenter から取得した Presentation Structure を状態としての Entity 変換用の Translator に渡し、戻り値をインスタンスとして保持する
    • 例: Entity から Presentation レイヤー用の Structure を抽出し、Presenter に渡す
  • UseCase レイヤーに定義された Presenter 用 interface
    • Presenter が依存すべき抽象が持つ処理を呼び出す
    • 例: タッチイベント通知用 Observable を購読
    • 例: Presentation レイヤー用に変換した Entity を描画させるために渡す
  • UseCase レイヤーに定義された Repository 用 interface
    • Repository が依存すべき抽象が持つ処理を呼び出す
    • 例: 外部データ読み込み完了通知用 Observable を購読
    • 例: Data レイヤー用に変換した Structure をストレージに永続化させるために渡す

Domain > Translator

Entity と Structure を相互に変換する ためのレイヤーです。
UseCase からの命令を受けて、必要なインスタンスを構築します。
外部データや描画構成の変更に対して UseCase レイヤーへの修正が伴わないようにするために設置されたレイヤーです。

責務

  • Entity から Presentation Structure を抽出する
  • Entity から Data Structure を抽出する
  • Presentation Structure から Entity を構成する
  • Data Structure から Entity を構成する
  • Presentation Structure から Data Structure に変換する
  • Data Structure から Presentation Structure に変換する

関心

  • Entity
    • 0個以上の Structure やプリミティブな値を基にして、Entity を構築します
  • Presentation Structure
    • 0個以上の Entity や Structure やプリミティブな値を基にして、Presentation Structure を構築します
  • Data Structure
    • 0個以上の Entity や Structure やプリミティブな値を基にして、Data Structure を構築します

Presentation > Presenter

View と UseCase を繋ぐ ためのレイヤーです。
UseCase からの命令を受けて利用すべき View の Observable を返す、という橋渡しを行います。
また、UseCase から Presentation Structure などを受け取り View に渡す、という橋渡しも行います。

責務

  • 任意のイベント実行を通知する Observable を UseCase に渡す
    • 例: 閉じるボタンタップメソッドの呼び出しを通知するメソッドを公開する
  • UseCase から渡されるデータを View に渡す
    • 例: 経過時間管理 UseCase が提供する経過時間を View に渡す

関心

  • UseCase レイヤーに定義された Presenter 用 interface
    • UseCase が要求する命令を処理するために必要なメソッドを公開する
  • Presenter レイヤーに定義された View 用 interface
    • UseCase から渡されたデータを View に橋渡しする

Presentation > View

見た目の制御や入力イベント処理などのユーザと直接的に対話する 処理を行うためのレイヤーです。
主な責務としては、イベントが発生した際にその旨を Presenter に通知したり、 Presenter から通知された描画命令に従い Presentation Structure などを描画します。
理想としては、子要素以外の他の View について知るべきではありません。

責務

  • 画面などに表示する要素の描画
    • 例: 時間が1秒進んだら渡される現在秒数に該当する Sprite を画面に描画する
  • ユーザからの入力の処理
    • 例: 閉じるボタンに対してタップイベントが発生したことを通知するメソッドを公開する
  • 構造的に近接する要素の生成・破棄
    • 例: 初期化時にリストの子要素となるアイテムを Instantiate する

関心

  • Presenter レイヤーに定義された View 用 interface
    • Presenter が要求する命令を処理するために必要なメソッドを公開する
  • Presentation Structure
    • 描画に関わるデータのまとまりとして Presenter から渡される

Domain > Repository

UseCase と DataStore を繋ぐ ためのレイヤーです。
単一の DataStore とやり取りをするだけの単なるインタフェース的な Repository もあれば、状況に応じて複数の DataStore とやり取りする Repository も存在し得ます。

責務

  • DataStore から Data Structure を取得する
    • DataStore がどのような手段で取得しているのかは関知しない
  • DataStore に Data Structure を格納する
    • DataStore がどのような手段で格納しているのかは関知しない

関心

  • UseCase レイヤーに定義された Repository 用 interface
    • UseCase が要求する命令を処理するために必要なメソッドを公開する
  • Repository レイヤーに定義された DataStore 用 interface
    • 複数の DataStore を条件に応じて切り替えつつ取り扱う
    • 例: 「ローカルストレージ DataStore に問い合わせて、キャッシュがあるならそれを使い、キャッシュしていないならば WebAPI DataStore から取得する」

Data > DataStore

外部システムからデータを取得し Data Structure のインスタンス構築に必要なデータを取得したり、Data Structure によってもたらされるデータを外部システムに保存・永続化するレイヤーです。
外部システムとの対話の仕方を知っており、プロダクトの中の世界と外の世界を繋ぐ唯一のレイヤーとなります。

責務

  • 外部システムと対話し、Data Structure のインスタンス構築に必要なデータを取得したり、Data Structure のインスタンスからもたらされるデータを永続化したりする
    • 例: サーバから取得した JSON 形式の文字列をプリミティブな型データにデシリアライズして Repository に渡す
    • 例: Repository から渡されるプリミティブな型データを JSON 形式の文字列にシリアライズしてローカルストレージに保存する

関心

  • Repository レイヤーに定義された DataStore 用 interface
    • 例: WebAPI から取得したデータを JsonUtility.FromJson メソッドを用いてデシリアライズする
    • 例: プリミティブな型データを JsonUtility.ToJson メソッドを用いてシリアライズする
  • Data Structure
    • 処理すべきデータのまとまりとして Repository から渡される