アプリ開発は「まずコンポジション」— 継承は“例外”にしよう
対象読者
C# や Unity でオブジェクト指向を学び始め、「クラス継承」を覚えたばかりの人
(変数・条件分岐・ループ・配列あたりまで習得済みを想定)
目次
TL;DR ― これだけ覚えよう
- アプリ側の設計はコンポジション(部品の組み合わせ)を基本とし、継承は“特別なケース”に限る。
- 継承は便利そうに見えるが、後から修正しにくい「副作用」が多い。
1. 継承とコンポジションって何?
用語 | ひとことで言うと | イメージ例 |
---|---|---|
継承 | 既存クラスを「そのまま伸ばす」 | Word の「別名保存」機能でテンプレを改造 |
コンポジション | 小さな部品を「組み合わせる」 | レゴブロックで好きな形を作る |
2. 継承を避ける 5 つの理由(かみ砕き版)
# | 何が困る? | 初心者向け解説 |
---|---|---|
1 | 親クラス変更=全崩れ | 親に新しい変数を足したら、子が全部エラーに… |
2 | 隠れ依存が増殖 | protected で共有すると「どこで変わるの?」地獄に |
3 | 名前衝突バグ | new と override を間違えやすい |
4 | テストしづらい | モック(仮のクラス)で差し替えられない |
5 | 無駄メモリ | 使わないフィールドまで継承してしまう |
3. コンポジションで動作を差し替えるサンプル
// ① 動きを表す「部品」
interface IMoveBehavior { void Move(); }
class Walk : IMoveBehavior { public void Move() => Console.WriteLine("歩く"); }
class Fly : IMoveBehavior { public void Move() => Console.WriteLine("飛ぶ"); }
// ② モンスター本体は部品を“入れ替え可能”に
class Monster
{
public IMoveBehavior Behavior { get; set; }
public void Act() => Behavior.Move();
}
// ③ 使うとき
var slime = new Monster { Behavior = new Walk() };
var dragon = new Monster { Behavior = new Fly() };
- 行動を増やしたいときは部品クラスを足すだけ。既存コードは無改造で OK。
4. それでも継承がハマるケース
- テンプレートメソッドが必要(Framework が「差し込み口」を用意している)
- 純粋な is-a 関係が成り立つ(IOException は Exception の一種、など)
- 既存 API と互換を保つ必要がある
- フレームワークが継承前提(WPF の MarkupExtension など)
5. 迷ったらチェックリスト
- 公開クラスは sealed で派生禁止にできる?
- 「とりあえず共通」で親に詰め込んでいない?
- 派生階層が 2 段以上 になりそうなら再設計を検討。
- 将来、別ジャンルのアプリでも同じ継承が必要?
6. 学び始めた人へのアドバイス
- まずはコンポジションで組む。 動きや見た目を“部品”として差し替えられる設計を体験しよう。
- 「冗長だな」と感じたら 抽象クラスを1段だけ 検討。多段継承は封印。
- is-a? クイズを自分に出してみる。親を子に置き換えて意味が通れば継承候補。
まとめ
- 原則:コンポジション優先、継承は例外的手段。
- 判断基準は 保守性・テスト容易性・依存方向・拡張性。
- 深い階層や派生クラスの乱造が見えたら、早めにリファクタリングを検討しよう。
継承は鋭いナイフ、コンポジションは安全なハサミ。
日常開発はハサミで、ナイフは慎重に。
訪問数 3 回, 今日の訪問数 3回
ディスカッション
コメント一覧
まだ、コメントがありません