継承よりコンポジションを選ぶべき理由と実践例
オブジェクト指向プログラミングにおいて、「継承」より「コンポジション」を選択する設計手法が注目されています。この資料では、両者の違い、メリットとデメリット、Unityにおける実践例を通して、なぜコンポジションが推奨されるのかを解説します。
目次
1. 継承 (Inheritance)
特徴
- あるクラスを基に新しいクラスを作成し、そのクラスの性質や動作を引き継ぐ仕組み。
- 「○○は××である (is-a)」の関係を表現。
メリット
- コードの再利用: 共通の機能を親クラスにまとめることで効率的に再利用。
- 階層構造の表現: オブジェクトの階層関係を明示的に表現可能。
デメリット
- 柔軟性の欠如: 親クラスに強く依存し、変更が困難。
- 強い結合: 親クラスの変更が子クラスに波及。
- 多重継承の問題: 設計が複雑化し、バグの温床に。
2. コンポジション (Composition)
特徴
- 複数のオブジェクトを組み合わせて、新しい機能や振る舞いを実現。
- 「○○は××を持っている (has-a)」の関係を表現。
メリット
- 柔軟性: クラス間の結合が緩く、再利用性や変更に強い。
- 動的な振る舞い: 実行時に異なるコンポーネントを組み合わせ可能。
- 単一責任原則(SRP): 各コンポーネントが独立して役割を果たすため、設計がシンプル。
デメリット
- 初学者には難解: オブジェクト間の依存関係の設計が複雑化することも。
- コード量の増加: クラスやオブジェクト数が増える可能性。
3. Unityにおける実践例
Unityはコンポジションを基本とした設計を採用しており、GameObjectとComponentを組み合わせて柔軟なシステムを構築します。
継承を使った例
public class Enemy : MonoBehaviour
{
public void Attack() { ... }
}
public class Boss : Enemy
{
public void SpecialAttack() { ... }
}
問題点:
Boss
クラスがEnemy
に強く依存し、汎用性が低下。
コンポジションを使った例
public class Enemy : MonoBehaviour
{
public IAttackStrategy AttackStrategy { get; set; }
public void PerformAttack()
{
AttackStrategy.Attack();
}
}
public interface IAttackStrategy
{
void Attack();
}
public class NormalAttack : IAttackStrategy
{
public void Attack() { ... }
}
public class SpecialAttack : IAttackStrategy
{
public void Attack() { ... }
}
メリット:
AttackStrategy
を実行時に変更可能。- 再利用性が高く、拡張にも柔軟に対応。
4. どちらを選ぶべきか?
継承が適切な場合
- 「is-a」の関係が自然で明確な場合。
- クラスの階層構造が安定しており、変更の可能性が低い場合。
コンポジションが適切な場合
- 動的に振る舞いを変更する必要がある場合。
- 再利用性や柔軟性を重視したい場合。
- 設計が頻繁に変更される可能性がある場合。
5. 結論
「継承かコンポジションか」の選択は、プロジェクトの要件や設計思想によります。ただし、柔軟性や変更への対応を重視する場合、特にUnityのような環境では「コンポジション」が推奨されます。
適切な手法を選択することで、設計の品質を向上させ、保守性の高いコードを実現できます。
ディスカッション
コメント一覧
まだ、コメントがありません