ポリモーフィズム ぽりもーふぃずむ
簡単に言うとこんな感じ!
「同じ操作をしても、相手によって動きが変わる」ってことだよ!リモコンの「再生ボタン」を押すと、DVDプレーヤーなら映像が流れて、音楽プレーヤーなら音楽が流れるよね。呼び出す側は「再生して!」と言うだけで、あとは機器がよしなにやってくれる感じ!
ポリモーフィズムとは
ポリモーフィズム(Polymorphism) とは、オブジェクト指向プログラミングの根幹をなす概念のひとつで、「同じインターフェース(操作の窓口)を通じて、異なる型のオブジェクトが、それぞれ異なる振る舞いをする」性質のことです。語源はギリシャ語の「poly(多)+ morphe(形)」で、直訳すると「多態性」または「多相性」と呼ばれます。
たとえば、動物クラスに「鳴く」というメソッドがあったとします。犬クラスは「ワン!」、猫クラスは「ニャー!」と鳴く――でも呼び出す側のコードは「鳴け」と命令するだけ。どんな動物かをいちいち確認して分岐させる必要がありません。呼び出す側のコードをシンプルに保ちながら、振る舞いだけを差し替えられるのがポリモーフィズムの強みです。
ポリモーフィズムは、カプセル化・継承 と並ぶオブジェクト指向の三大原則の一角を担っています。「同じコードで将来追加されるクラスにも対応できる」という拡張性の高さが、大規模なシステム開発や長期メンテナンスで特に力を発揮します。
ポリモーフィズムの種類と仕組み
ポリモーフィズムには大きく分けて以下の種類があります。
| 種類 | 別名 | 概要 | 典型的な実現方法 |
|---|---|---|---|
| サブタイプ多態性 | 実行時多態性 | 親クラスの参照で子クラスのメソッドが呼ばれる | 継承+オーバーライド |
| パラメータ多態性 | ジェネリクス | 型を問わず同じアルゴリズムが使える | ジェネリクス・テンプレート |
| アドホック多態性 | オーバーロード | 同名メソッドを引数の型や数で使い分ける | メソッドオーバーロード |
実務でもっともよく使われるのは サブタイプ多態性 です。以下のPythonコードで雰囲気をつかんでみましょう。
# 親クラス
class Animal:
def speak(self):
raise NotImplementedError
# 子クラスがそれぞれ「鳴き方」を上書き(オーバーライド)
class Dog(Animal):
def speak(self):
return "ワン!"
class Cat(Animal):
def speak(self):
return "ニャー!"
# 呼び出す側は「Animalのリスト」として扱うだけ
animals = [Dog(), Cat(), Dog()]
for a in animals:
print(a.speak()) # → ワン! ニャー! ワン!
for ループは「犬か猫か」を知らなくても動きます。これがポリモーフィズムの本質です。
覚え方:「リモコンの再生ボタン」
「再生ボタン(共通インターフェース)を押すと、つないでいる機器(クラス)によって動作が変わる」――このイメージで覚えましょう。呼ぶ側はボタンひとつ、応える側が自分のルールで動く、それがポリモーフィズムです。
動的ディスパッチ:実行時に「誰が動くか」が決まる
ポリモーフィズムが実現される背景には 動的ディスパッチ(Dynamic Dispatch) という仕組みがあります。コードを書く段階(コンパイル時)ではなく、プログラムが動いている段階(実行時)に「このオブジェクトはどのクラスのメソッドを呼ぶか」を決定します。これによって、将来新しいクラスを追加しても既存のコードを一切変えずに対応できます。
歴史と背景
- 1960年代後半 — Simula 67(世界初のオブジェクト指向言語)が登場。クラスと継承の概念を導入し、ポリモーフィズムの基礎が生まれる
- 1970年代 — Smalltalkがポリモーフィズムを言語の中核に据え、「メッセージパッシング」という形で洗練させる
- 1980年代 — C++の普及により、オーバーライド・仮想関数(virtual function)として広く認知される
- 1995年 — JavaがインターフェースとポリモーフィズムをWeb時代の主流言語として広める。「同じコードを書かずに済む」という実務上の価値が注目される
- 2000年代以降 — Python、Ruby、C#、Kotlinなど主要言語すべてがポリモーフィズムを標準的にサポート。デザインパターン(StrategyパターンやFactoryパターン等)の基盤技術として不可欠に
継承・インターフェースとの関係
ポリモーフィズムは単独では成立せず、継承 や インターフェース と組み合わせて使います。それぞれの役割と関係を整理します。
| 概念 | 役割 | ポリモーフィズムとの関係 |
|---|---|---|
| 継承 | 親クラスの属性・メソッドを子が引き継ぐ | サブタイプ多態性の基盤 |
| オーバーライド | 子クラスが親のメソッドを上書き | ポリモーフィズムを実際に動かす仕組み |
| インターフェース | 「このメソッドを持つこと」という契約 | 継承なしでポリモーフィズムを実現 |
| 抽象クラス | 一部を未実装にした親クラス | インターフェースに近い使い方が可能 |
ビジネス現場での活用イメージ
システム発注や仕様検討の場面で「ポリモーフィズムを使う設計にしてほしい」という要求は、実は次のような意味を持ちます。
- 「将来の機能追加が楽になる設計」 ― 今は「メール通知」だけでも、後で「SMS通知」「Slack通知」を追加するとき、既存コードを変えずに済む
- 「テストが書きやすくなる設計」 ― 本物の決済サービスの代わりにダミークラスを差し込める(モック)
- 「担当者が変わっても読みやすいコード」 ― 条件分岐(if/switch)が減り、コードがすっきりする
【ポリモーフィズムが活きる場面】
if 通知タイプ == "メール":
メール送信() ← ← これが増え続けるとカオスに…
elif 通知タイプ == "SMS":
SMS送信()
elif 通知タイプ == "Slack":
Slack送信()
↓ ポリモーフィズムを使うと…
通知オブジェクト.send() ← 呼ぶ側は1行で済む!
(Emailクラス・SMSクラス・Slackクラスが各自で動く)
関連用語
- ./044-oop.md — オブジェクト指向プログラミング(OOP)― ポリモーフィズムが属するプログラミングパラダイム
- ./045-class-inheritance.md — 継承 ― ポリモーフィズムを実現する中心的な仕組み
- ./047-encapsulation.md — カプセル化 ― OOPの三大原則のひとつ。ポリモーフィズムと並ぶ柱
- ./048-interface.md — インターフェース ― 継承を使わずにポリモーフィズムを実現する「契約」の仕組み
- ./049-abstract-class.md — 抽象クラス ― 一部を未実装にした親クラス。ポリモーフィズムの土台として使われる
- ./050-design-pattern.md — デザインパターン ― StrategyパターンやFactoryパターンなど、ポリモーフィズムを活用した設計のお手本集
- ./051-override.md — オーバーライド ― 子クラスが親クラスのメソッドを上書きする仕組み。ポリモーフィズムの実働部隊