クラス設計

クラスとは

データとロジックを1つのプログラミング単位にまとめる仕組み。

良いクラス設計とは

本記事は把握しやすく変更に強いクラスを 良いクラス と考える。

  • 各クラスの役割が明確(関心ごとを分離、単一責任の原則)
  • 各クラスの依存関係が適切(本記事の主題)

依存関係とは

クラス A がクラス B のメンバーを呼び出しているとき、クラス A はクラス B に依存していると呼ぶ。

graph LR
    A(A) --> B(B)

(A→Bの)依存関係の原則

  • クラス B の変更はクラス A に影響する
  • クラス A の変更はクラス B に影響しない(クラス Bはクラス A を知らなくてよい

良くない依存関係

影響範囲が広く・複雑な依存関係。

  • 多すぎる依存
  • 循環依存

良い依存関係

依存関係が安定している。

不安定な依存とは

  • 変更を受けやすいクラスへの依存
  • 自分でコントロールできないクラスへの依存

上記の例はアプリケーションの入出力に近いクラス( UI, DB, WEB API )。

  • 詳細への依存

依存関係をコントロール

制御の流れと(安定した)良い依存関係が一致しない場合がある。 良い依存関係を実現するために依存をコントロールする必要がある。 おもに 依存性逆転の原則 を使う。

依存関係逆転の原則

例:改善前

制御:UIから始まり、データの取得、永続化へと続く一連の処理フローを示 UI → Fetcher → API Client → Domain(Account/Costs) → DB Writer

  • UI (ユーザーインターフェース)
  • Fetcher がデータを取得する役割を担う(ユースケース)
  • API Client が外部のAPIと通信(外部の影響を受ける不安定なクラス)
  • Account や Costs といったデータモデル
  • DB Writer がデータベースへの書き込み(永続化)

上記の制御の流れではアプリケーションのユースケース Fetcher がコントールが難しい外部 API と通信するクラス API Client に依存している。 依存関係逆転の法則を使用して依存の向きをコントーロール(逆転)する

改善後

unnamed

Fetcher(上位モジュール)が API Client(下位で不安定なモジュール)に依存するのではなく、間にインターフェースを挟むことで、依存関係の方向を逆転させている。これにより、API Client のような不安定な部分の変更が Fetcher に影響を与えにくくなり、システム全体が安定する。

逆転とは API Client インターフェースの所有者を API Client ではなく方針をしめしている Fetcher と考えることで API Client が Fetcher(が提供しているインターレース)に依存していると考えることができる。

依存性の逆転は現代のフレームワークでは DI( Symfony のサービスコンテナの機能の一つ)で実現。