コンテンツにスキップ

判断ガイド: 継承かコンポジションか

判断フロー

Q1. 目的は「抽象(インターフェース)の実装」か?
    → はい ──> 継承でよい(純粋仮想の実装は健全な継承)
Q2. 目的は「実装(コード)の再利用」か?
    → はい ──> コンポジション(部品として持つ)を既定とする。Q3で例外確認
Q3. 例外チェック: 次の3条件が全部成り立つか?
    (a) is-aが契約レベルで成立([LSP](../02_solid/lsp.md): 置換しても呼び出し側の期待を破らない)
    (b) 階層は浅い(1〜2段)まま安定しそう
    (c) 基底の変更が派生を壊す結合を受け入れられる(同一チーム・同時変更が可能)
    → 全部Yes ──> 継承も可(Template Method型の骨格共有など)
    → 1つでもNo ──> コンポジション
Q4. 「特徴の組み合わせ」を表現したいか?(飛ぶ×撃つ×分裂)
    → はい ──> 迷わずコンポジション(継承ツリーは組み合わせで爆発する)

根拠: 継承・委譲・コンポジションLSPStrategy

判断材料

  • 継承の危険シグナル: 空実装のoverride/基底のprotectedメンバを派生が直接いじる/「〜だけど〜しない」型(飛べない鳥)/派生の追加のたび基底に条件分岐が増える
  • コンポジションの危険シグナル: 部品が2つで固定なのに差し替え基盤を整備/部品間の通信コードが本体より太い(部品の切り方=責務の切り方が誤り)

例外

  • フレームワーク規約: MonoBehaviour、AActor、Screen基底などエンジン・基盤の指定する継承は従う(規約への準拠であり、この判断の対象外)
  • バリエーション2つで固定: enum+ifの方が誠実なこともある(継承もコンポジションも過剰)

トレードオフ

継承 コンポジション
記述が短い、型で能力が分かる、フックの規約提供 組み合わせ自由、実行時差し替え、弱い結合
最強の結合(基底変更の波及)、組み合わせ爆発、実行時変更不可 部品接続コード、追跡の手間、設計力を要求

実践のコツ

  • 迷ったらコンポジション(戻しやすいのはこちら。継承を剥がすのは大工事)
  • 「継承で共有したい実装」は、大抵部品クラス1つ+両者がそれを持つで書き直せる——書き直してみて不自然なら継承の兆候

理解度チェック

  1. 「インターフェースの実装」の継承が例外的に安全なのはなぜですか。
  2. Q3の3条件のうち、実務で最も破られやすいのはどれだと思いますか。
  3. 継承もコンポジションも過剰な状況とは?

前: インターフェースを作るべきか | カテゴリ目次 | 次: 抽象化すべきか・パターンを使うべきか