ポリモーフィズムとは
ウィキペディアにはこう書いてありました。
ポリモーフィズム(英: Polymorphism)とは、プログラミング言語の型システムの性質を表すもので、プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。
「プログラミング言語の各要素についてそれらが複数の型に属する」という点が難しいですが。
要するに、ポリモーフィズムとは、共通メインルーチンのことです。
共通メインルーチンとは?
- 共通サブルーチンと逆の発想。
- 呼び出し方は一通りだが、呼び出されるもの(メソッド)は複数通りある。
なぜポリモーフィズムを使うのか
- 呼び出される側(クラス、メソッド)が増えても、呼び出し元のコードは変えなくていい。
- つまり、プログラムの修正やテストにかかるコストを減らせる。
ポリモーフィズムの実装
- 通常、生成したインスタンスを変数に代入する場合、その変数の型は生成したインスタンスと合わせる必要があります。
Door dr = new Door(); // OK: 左辺と右辺の型が一致(注:Doorは自作クラス)
Door dr2 = new String(); // NG: 左辺と右辺の型が不一致なのでコンパイルエラー
- ポリモーフィズムを使うと、左辺と右辺の型が異なっていても、代入できます。
- 正確にいうと、その2つのクラスは継承関係である必要があります。
ClassA a = new ClassB(); // OK
// ClassAがスーパークラス、ClassBがサブクラス
public class ClassB extends ClassA {
// 省略
}
ポリモーフィズムの具体例
1. ポリモーフィズムを利用した配列
呼び出し元(メインメソッドがあるクラス)
- 処理(1)について
変数playersは「Playerクラスの配列」で宣言しています。
その配列の中身には、別のクラス(Playerクラスのサブクラス)のインスタンスを代入しています。
- 処理(2)について
ここがポリモーフィズム(共通メインルーチン)です。
「players[X].janken()」と呼び出し方は一通りだが、呼び出されるメソッドは複数(Personのじゃんけん、Robotのじゃんけん)あります。
public class MainClass {
public static void main(String[] args) {
// (1) じゃんけんするプレイヤーを生成
Player[] players = new Player[3];
players[0] = new Person(); // 人
players[1] = new Robot(); // ロボットA
players[2] = new Robot(); // ロボットB
// (2) 各プレイヤーが順番にじゃんけんさせる
players[0].janken(); // 人
players[1].janken(); // ロボットA
players[2].janken(); // ロボットB
}
}
呼び出し先(スーパークラス)
public class Player {
private int win;
public void janken() {
// じゃんけんの処理
}
public int getWin() {
return win;
}
}
呼び出し先(サブクラス)
public class Person extends Player {
// 省略
}
public class Robot extends Player {
// 省略
}
今後、jankenメソッドの処理が変わっても、呼び出し元は(1)も(2)も変更しなくて済みます。
また、以下のようにプログラム修正があっても、呼び出し元コードは(1)箇所だけ変えればよいです。
- プレイヤーの人数が変更(例:3名から10名)
- プレイヤーの種別が変更(例:人やロボットに加え、人工知能、猿、宇宙人・・・など)
- 注意:もちろん、呼び出され側は、人工知能クラスを作るなどの変更は必要です。
2. 引数でポリモーフィズムを利用した例
先ほどのじゃんけんプログラムに仕様変更があったとします。
先ほどのMainClass.javaに「【追加】」のコードを追記しました。
- Entryクラスのコンストラクタは、Playerクラスの引数を要求しています。
- 実際には、Playerクラスのサブクラスを引数に設定できています。
- 繰り返しになりますが、今後サブクラスが増えたとしても、呼び出し元コードの書き方は同じです。
public class MainClass {
public static void main(String[] args) {
// (1) じゃんけんするプレイヤーを生成
Player[] players = new Player[3];
players[0] = new Person(); // 人
players[1] = new Robot(); // ロボットA
players[2] = new Robot(); // ロボットB
// 【追加】じゃんけん大会に登録する処理を追加
Entry[] entry = new Entry[3];
entry[0] = new Entry(players[0]); // 人
entry[1] = new Entry(players[1]); // ロボットA
entry[2] = new Entry(players[2]); // ロボットB
// (2) 各プレイヤーが順番にじゃんけんさせる
players[0].janken(); // 人
players[1].janken(); // ロボットA
players[2].janken(); // ロボットB
}
}
public class Entry {
private int win;
// コンストラクタ
public Entry(Player player) {
// じゃんけん大会に登録するためにプレイヤーの情報(勝利数の履歴など)を取得
win = player.getWin();
}
}
まとめ
ポリモーフィズムとは?
- 共通メインルーチンです。
- 呼び出し方は一通りの記述で統一できます。
- 呼び出されるもの(メソッド)は複数通りあります。
なぜポリモーフィズムを使うのか?
- 呼び出されるものが変わっても、呼び出し元のコードは変えなくていいためです。
- プログラムの修正やテストにかかるコストを減らせるためです。これは、実務では非常に重要な観点です。
参考文献
- Head First Java 第2版 ―頭とからだで覚えるJavaの基本
- オブジェクト指向でなぜつくるのか 第2版
オブジェクト指向をもっと勉強したい方は一読をオススメします。
Amazonで購入できます。