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

Releases: umm/cafu_core

v3.1.0

10 Mar 15:48
Compare
Choose a tag to compare
  • Support UPM

Re-review the definition of Clean Architecture

11 Sep 10:36
Compare
Choose a tag to compare

Dependency Inversion Principle for Presentation Layers

What?

  • 所謂「依存性逆転の原則」(Clean Architecture 本 P.103 参照)
  • Presentation レイヤーの依存の向きを逆にする
    • 参照の持ち方が完全に逆転する

Why?

  • 本来的に Clean Architecture が定義する依存の単一方向性からズレてしまっていたから
    • 本来は View --> Presenter --> UseCase や DataStore --> Repository --> UseCase となるべき
    • Wiki 参照
  • 加えて、interface の定義場所が DIP: Dependency Inversion Principle (依存性逆転の原則)のルールに従い切れていなかったので、それも修正
    • 本来は依存される側の namespace に interface を配置して、依存する側が namespace を跨ぐべき

Before

namespace UseCase
{
    public interface IHogeUseCase {}

    public class HogeUseCase : IHogeUseCase
    {
    }
}

namespace Presenter
{
    public interface IFugaPresenter {}

    public class FugaPresenter : IFugaPresenter
    {
        private IHogeUseCase HogeUseCase { get; }
    }
}

namespace View
{
    public interface IPiyoView {} // 実際に View の interface が切られることは無かった…かな?
    public class PiyoView : IPiyoView
    {
        private IFugaPresenter FugaPresenter { get; }
    }
}

After

namespace UseCase
{
    // 最悪なくても良いが、テストする時に必要になる
    public interface IHogeUseCase {}

    // UseCase 的に「こういう振る舞いを持っていて欲しい Presenter」を定義
    // 実際には、Suffix として Presenter を付けずに I<Actor><Behaviour> とするのが理想…かな?
    //   IMoleImageRenderer とか IWebCamInitializer とか?
    public interface IFugaPresenter {}

    public class HogeUseCase : IHogeUseCase
    {
        private IFugaPresenter FugaPresenter { get; }

        // Zenject で DI しちゃうのがヨサソウ
        public HogeUseCase(IFugaPresenter fugaPresenter)
        {
            FugaPresenter = fugaPresenter;
        }
    }
}

namespace Presenter
{
    // Presenter 的に「こういう振る舞いを持っていて欲しい View」を定義
    // 実際には、Suffix として View を付けずに I<Verb><Actor><Behaviour> とするのが理想…かな?
    //   ITransitionSceneTrigger とか IPlayTutorialTrigger とか?
    public interface IPiyoView {}

    public class FugaPresenter : IFugaPresenter
    {
        private IPiyoView PiyoView { get; }

        // これも DI で
        public FugaPresenter(IPiyoView piyoView)
        {
            PiyoView = piyoView;
        }
    }
}

namespace View
{
    public class PiyoView : IPiyoView
    {
    }
}
  • Zenject の Constructor Injection を使うとキレイになる
    • とはいえ、開発時はフィールド増える度にコンストラクタを修正する必要が出てくるので面倒
    • なので、開発時は [Inject] 属性でプロパティに DI しておいて、リファクタリングフェーズでコンストラクタに移動するとかが筋が良いかも

Flatten interfaces

What?

  • 各レイヤを表現する基底 interface の配置をフラットにする
    • CAFU.Core.Domain.UseCase.IUseCaseCAFU.Core.IUseCase 的な。

Why?

  • 現状の interface 群は「役割を表現するための型」であり、クラスのインタフェースを表現するためのモノではないため、namespace をネストさせると混乱を招くという判断もある
  • また、 v2 と v3 の共存を睨んで、同一の型名が存在しないようにしたかった想いもある

IEntity, IStructure

What?

  • Entity レイヤを UseCase よりも更に上の概念として切り出す
  • 各レイヤを跨ぐデータの受け渡しは Entity を直接用いずに、専用の構造体(まぁクラスでも良いけど)を用いて行う
  • 各 UseCase 間で Entity を経由して処理の受け渡しを行う
    • 具体的には、 FooUseCaseIHogeEntity.FugaSubject.OnNext() して BarUseCaseIHogeEntity.FugaSubject.Subscribe() を行う、みたいなイメージ
      • まぁ、ココも本当は Subject を経由せずに Fuga()OnFugaAsObservable() とかした方が良いのかも知れないけど、面倒なのでそこは Subject に任せちゃってもヨサソウ
  • また、これに伴い Entity の宣言箇所を Domain 配下に移動する
    • Foo.Data.EntityFoo.Domain.Entity

IEntity

  • Entity は「状態の管理」や「Entity に閉じた処理」を行うクラスとして定義される
  • Actor に閉じているべきで、複数の役割を持たせないコトが肝要

IStructure

  • Structure は「値の管理」を行うデータ構造として定義される
    • IDictionary<TKey, TParam> やプリミティブな値のみで処理できる場合は不要
    • ちょっと複雑なデータ構造を受け渡しする場合や、受け渡しするデータに対して明確な意味づけをしたい場合に用いる
  • 基本的にメソッドを持たずにフィールド・プロパティのみを持つ
  • IObservable や Action/Func を持つのはアリ

Why?

  • SRP: Single Responsibility Principle に従い、責務を分離したかったため
  • UseCase で状態を管理せずに、Entity で管理することで、処理と状態の分離も図る

Add IResolver

What?

  • IResolver<TParam1, TParam2, ..., TConcrete> なインタフェースを追加
  • 例えば画像の読み込みに際して、「サーバから取得する ImageFromHttpDataStore」と「キャッシュから読む ImageFromLocalCacheDataStore」とを切り替える必要がある場合に、「キャッシュの有無」によってどちらの DataStore を返すのかを処理するためのレイヤ
  • イメージとしては Factory に近いが、都度インスタンスを生成するわけではなく、Resolver 側にそれぞれの DataStore のインスタンスを Inject しておくコトで効率化を図ったりする

Why?

  • チョイチョイ使う割に名前がなかったので、レイヤーとして切り出して名前を与えたかった

IModel

What?

  • CAFU.Core.Domain.Model.IModel を削除

Why?

  • Entity と Structure の分離により、不要となるので削除

View.Controller

What?

  • CAFU.Core.Pesentation.View.Controller を削除

Why?

  • Zenject により Presenter の初期化が不要になったため

Rename Translator interfaces

29 May 09:10
Compare
Choose a tag to compare

Changes

  • #42 Rename IAsync(Model|Entity)Translator to IObservable(Model|Entity)Translator
  • #42 Add IAsync(Model|Entity)Translator for System.Threading.Tasks.Task

Add DataStoreResolver

18 May 10:08
Compare
Choose a tag to compare

Features

  • #39 Add DataStoreResolver

メモリリークを修正

06 Mar 11:12
Compare
Choose a tag to compare

Fixes

  • 画面遷移時(シーンが閉じられるとき)に Resources.UnloadUnusedAssets() を叩くことで、不要なアセットによるメモリ圧迫を低減する

@umm/unirx_observablelifecyclemonobehaviour を更新

20 Feb 15:56
Compare
Choose a tag to compare

Changes

  • @umm/unirx_observablelifecyclemonobehaviour を v1.0.2 に更新