【オブジェクト指向】継承、コンポジションの違いと使用方法

公開日: 2025/5/9

まずはじめに、オブジェクト指向言語とはソフトウェアの考え方で「さまざまな処理を部品ごとに分けて、それらを1つにまとめプログラミングしていくという考え方」を表しています。

よく自動車の例が挙げられていますが、ほとんど同じですがここでは自動販売機を例にあげてみます。


まずは自動販売機の動作をおさらいしてみますが、「お金を入れる」→「購入できる飲み物のボタンが光る」→「ボタンが押されたら飲み物が出てくる」というようなものが共通の動作としてあると思います。

この共通の動作を色々な自動販売機に流用していくというのがオブジェクト指向の考え方です。

「お金を入れる」処理を1000円ガチャなどに流用すると、小銭が使えなくお札のみ使用できるという処理を1から作らずに応用して作成することができます。

こういった考え方をプログラムに落としたものがオブジェクト指向といいます。


今回はその中で、「継承」、「コンポジション」についてそれぞれの違いと使用方法について簡単に説明していきます。

1. 継承


継承とは、既存のクラスから、新しく作ったクラスに「変数定義」や「メソッド」などを引き継ぐことです。

継承される既存のクラスを「スーパークラス(親クラス)」、継承して新しく作ったクラスを「サブクラス」といいます。


例を挙げて説明します。

棒人間のゲームを作るとします。もちろん最初は何も装備していない棒人間のキャラクターを作ると思います。

これが、親クラスです。

次に親クラスで作った棒人間を元にして、おしゃれな剣が使える棒人間、魔法が使える棒人間を作成すると思います。

その時に、また一から棒人間を作るより、何も装備していない棒人間に剣や杖を装備していく方が楽になると思います。これが継承になります。

何も装備していない棒人間を継承して、新しい棒人間を作るというような考え方のことです。


では親クラスを継承することでどういったメリットがあるのか解説します。

2. メリット


1.可読性

実際は、継承を使わずにコードを書くことは可能です。

ただ、別のクラスとはいえ同じ処理を何度も書いてしまうとかなり読みにくくなってしまいます。

その際、継承をしようするとコードが読みやすくなります。

先ほどの例でいうと、何度も棒人間を一からデザインするということです。

2.保守性

継承を上手く使うと、コードの修正や追加が簡単になります。

もしメソッドの呼び出し順番が変わったとします。

その際でも親クラスにメインの処理が書いてあれば、大きく書き直すことが最小限になります。

そのため保守性、メンテナンスしやすいコードになります。

先ほどの例で言うと、剣士に間違えて杖を装備させてしまったとします。

杖を剣に変える時、元々棒人間は継承しているため杖を剣に変える処理だけですみます。

3.再利用性

継承を使うと、コードを再利用することができます。

親クラスに書いた処理を子クラスに引き継ぐことが可能ですので、同じ処理を親クラスにまとめることで新たに子クラスで実装する必要がなくなります。

子クラスで新しく処理を書く必要がないのです。

3. コンポジション


続いてコンポジションについて説明します。

コンポジションとは混合物を意味するオブジェクト指向の一つで、あるクラスの機能を持つクラスのことを指しています。

特定クラスの機能を、自分が作るクラスにも持たせたい場合に、継承を使わずにフィールドとしてそのクラスを持ち、そのクラスのメソッドを呼び出すメソッドを持たせることで、クラスに他のクラスの機能を組み込むことができます。

継承と似てるところが多いですが違う考え方になります。

スーパークラスの機能そのものを別のクラスで使いたい場合は継承を使用しますが、スーパークラスの一部の機能を使用したい場合にはコンポジションを使用します。


まずは、継承をする際はどういった時に使用するかです。

1. 「is-a」の関係が成り立つ場合:

サブクラスがスーパークラスの特化であり、特定の機能や性質を拡張する場合。

2. コードの再利用が容易である場合:

スーパークラスのメソッドや属性をサブクラスで再利用する必要がある場合。


続いて、コンポジションを使用する場合の説明です。

1. 「has-a」の関係が適している場合:

オブジェクトが他のオブジェクトを持っているが、直接の継承関係が成り立たない場合。

2. 柔軟性と変更の容易さが求められる場合:

コンポジションは静的な継承よりも柔軟で、クラスの変更が他のクラスに与える影響が少ない。

3. 複数の実装から選択できる場合:

インターフェースや抽象クラスを使用し、異なる実装をコンポジションによって組み合わせることができる。


先ほどの棒人間の例から考えてみると、棒人間そのものを使用してキャラメイクしたい場合は継承を使用して、棒人間が使うパンチを使用して別の技を作りたい時にはコンポジションを使用します。

簡単に説明するとこれが継承とコンポジションの使い分け方法になります。

では最後に実際のコードを見てみましょう。

今回はPythonで表示してみます。

先ほどの例で示したキャラクターメイクを例に挙げています。

4. 使用例

まずは継承からです。

# 基本クラス: キャラクター
class Character:
    def __init__(self, name, level):
        self.name = name
        self.level = level

    def describe(self):
        return f"{self.name} (レベル {self.level})"

    def attack(self):
        raise NotImplementedError("サブクラスで実装する必要があります")

このクラスでは基本的なキャラクターの情報を定義しています。

この定義した情報をもとに、戦士と魔法使いを定義します。


まずは戦士です。

# Characterクラスを継承したサブクラス: 戦士
class Warrior(Character):
    def __init__(self, name, level, weapon):
        super().__init__(name, level)
        self.weapon = weapon

    def attack(self):
        return f"{self.name} は {self.weapon} で攻撃する!"

次に魔法使いです。

# Characterクラスを継承したサブクラス: 魔法使い
class Wizard(Character):
    def __init__(self, name, level, magic_type):
        super().__init__(name, level)
        self.magic_type = magic_type

    def attack(self):
        return f"{self.name} は {self.magic_type} の魔法を唱える!"

最後に継承とは関係ありませんが、キャラクターを作ります。

# 戦士のインスタンスを作成して利用する例
warrior = Warrior("クレイ", 10, "剣")
print(warrior.describe())   # 出力: クレイ (レベル 10)
print(warrior.attack())     # 出力: クレイ は 剣 で攻撃する!

# 魔法使いのインスタンスを作成して利用する例
wizard = Wizard("リアナ", 12, "火の魔法")
print(wizard.describe())    # 出力: リアナ (レベル 12)
print(wizard.attack())      # 出力: リアナ は 火の魔法 を唱える!

つづいて、コンポジションの例を先ほどのコードを変えて、コンポジションについて例を挙げてみます。

#

5. まとめ

今回は継承とコンポジションについて簡単にまとめてみました。

詳細な違いはもっとありますが、分かりやすく説明したつもりです。

継承とコンポジションはデザインパターンについて学習するのに必要な知識になりますので、ぜひ覚えて帰ってください。