本文へスキップ
BecomeCoder

Java MVVMコース · 第10章 仕上げ ― アプリを完成させる · レッスン39

全層を振り返る ― 依存の向きをもう一度確認する

ローカル実施

導入

ここまでの9章で、タスク管理アプリは「テストだけを頼りに動くものを積み上げる」というやり方で完成に近づきました。仕上げに入る前に、一度立ち止まって全体を見渡しましょう。バラバラに見えていたEntity・Repository・Service・ViewModel・Viewが、実は1つの一貫した依存の向きのルールでつながっていたことに気づけるはずです。

説明

flowchart LR
    subgraph SUP["app.support(何にも依存しない)"]
        ID["IdGenerator / Clock(抽象)"]
    end
    subgraph DOM["app.domain"]
        TT["TaskTitle / Priority<br/>(値オブジェクト)"]
        TI["TaskItem<br/>(Entity)"]
        FAC["TaskFactory"]
    end
    subgraph REPO["app.repository"]
        ITR["TaskRepository(抽象)"]
        IMR["InMemoryTaskRepository(実装)"]
    end
    subgraph SVC["app.service"]
        TS["TaskService"]
        DTO["TaskDto / TaskMapper"]
    end
    subgraph VM["app.viewmodel"]
        TLV["TaskListViewModel"]
        CMD["Command / RelayCommand"]
    end
    subgraph VIEW["app.view / app(Composition Root)"]
        FXML["FXML + Controller"]
        MAIN["Main(依存を組み立てる場所)"]
    end
    FAC --> TI --> TT
    TI --> ID
    FAC --> ID
    IMR -.実装.-> ITR
    TS -->|使う| ITR
    TS --> DTO
    TLV -->|使う| TS
    TLV --> CMD
    FXML <-->|バインディング| TLV
    MAIN -.配線.-> IMR
    MAIN -.配線.-> TS
    MAIN -.配線.-> TLV
  • support(第1章): IdGeneratorClock。何にも依存しない、最も外部技術に近い抽象
  • Entity/ValueObject(第2章): TaskItemTaskTitlePriority。業務データそのものと、それが必ず守るべきルールを持つ
  • Factory(第3章): TaskFactory。生成のルールを1箇所にまとめ、IdGeneratorを注入される
  • Repository(第4章): TaskRepository(抽象)とInMemoryTaskRepository(実装)。データの出し入れだけを担当し、業務ルールは持たない
  • Service(第5章): TaskService。複数のデータを見比べる業務ルールを担当する
  • ViewModel(第6章): TaskListViewModel。画面の状態(newTitletasks)と操作(Command)を、JavaFXに依存しない普通のJavaのクラスとして表現する
  • View(第7章): FXML+Controller。fx:idとバインディングでViewModelとつながるだけで、ロジックは持たない
  • DI/Composition Root(第8章): どの実装をどこに注入するかを、アプリ起動時のMainでまとめて決める
  • テスト(第9章): 各層は自分より内側(support/domain寄り)のインターフェースにしか依存しないため、外側をFakeやMockitoのモックに差し替えるだけで高速なテストが書けた

矢印の向きに注目してください。どの層も、自分より業務の核に近い層にしか依存していません。ViewはViewModelを知っていますが、ViewModelはViewの存在を知りません。ServiceはRepositoryのインターフェースを知っていますが、Repositoryの具体的な実装(InMemoryかDBか)は知りません。この「依存の向きを常に核へ集める」という1つのルールが、第1章のパッケージ分割からテストのしやすさまで、コース全体を貫いていました。

まとめ

  • support→domain→repository→service→viewmodel→viewは、すべて「自分より内側にしか依存しない」という1つのルールでつながっている
  • このルール(依存性逆転)のおかげで、外側(Repository・Service・View)をFakeや別実装に差し替えても、内側のコードは変更不要になる
  • 次のレッスンから、この構造を保ったまま新機能を2つ追加する

次回: 「期限切れ強調表示」機能をTDDで追加します。