継承とコンポジションの使い分け

オブジェクト指向プログラミング(OOP)における「継承(Inheritance)」と「コンポジション(Composition)」は、クラス同士の関係を構築する2つの主要な手法です。どちらもコードの再利用性を高める目的がありますが、使いどころや設計思想に違いがあるため、適切に使い分けることが重要です。


継承(Inheritance)とは

継承は、あるクラス(親クラス / スーパークラス)の機能や属性を、別のクラス(子クラス / サブクラス)が引き継ぐ仕組みです。

特徴:

  • 「is-a(〜である)」の関係を表現

  • 基底クラスの振る舞いを子クラスが再利用、または上書き(オーバーライド)可能

  • 多階層に渡る階層構造(継承チェーン)が作られることもある

利点:

  • コードの再利用性が高い

  • ポリモーフィズム(多態性)が自然に扱える

欠点:

  • 高い結合度(サブクラスがスーパークラスに強く依存)

  • 継承階層が深くなると理解・保守が困難になる(fragile base class 問題)


コンポジション(Composition)とは

コンポジションは、別のクラスのインスタンスをフィールドとして持つことで機能を再利用する手法です。

特徴:

  • 「has-a(〜を持つ)」の関係を表現

  • 動的に振る舞いを変更できる(戦略パターンなどで活用)

利点:

  • 柔軟性が高く、クラス間の結合度が低い(疎結合)

  • 実行時に構成を変更できる

  • 継承の階層構造に依存しないため保守性が高い

欠点:

  • 設計・実装がやや複雑になることがある

  • ポリモーフィズムを明示的に設計する必要がある(インターフェースとの併用)


継承とコンポジションの使い分け

判断軸 継承(Inheritance) コンポジション(Composition)
関係性 is-a(〜である) has-a(〜を持つ)
結合度 高い(密結合) 低い(疎結合)
柔軟性 低い(階層構造に依存) 高い(動的に変更可能)
再利用 基底クラスの再利用 機能単位の再利用
使用例 動物クラス → 猫クラス 車クラスがエンジンを持つ

実例

継承の例(is-a):

java
class Animal { void makeSound() { System.out.println("Some sound"); } } class Dog extends Animal { void makeSound() { System.out.println("Bark"); } }

コンポジションの例(has-a):

java
class Engine { void start() { System.out.println("Engine started"); } } class Car { private Engine engine = new Engine(); void drive() { engine.start(); } }

原則

OOP設計の原則として、**「継承よりもコンポジションを優先せよ(Favor composition over inheritance)」**という考え方が推奨されます。これは、システムの保守性と拡張性を高めるためのベストプラクティスです。


まとめ

  • 継承は階層的な分類や共通動作の再利用に適していますが、柔軟性に欠けることがあります。

  • コンポジションは疎結合で拡張性に優れており、特に動的な振る舞いの差し替えが必要な場合に有効です。

  • 長期的な保守・拡張を考慮する場合は、まずコンポジションを検討し、必要なら継承を使うのが望ましい設計アプローチです。

生成日:2025/06/01