ポリモーフィズム
「中に入るものによって同じメソッドでも違う処理を行える」というプログラミング言語自体の特徴のこと。
【説明】
結論、ポリモーフィズムは「 呼び出す関数が呼び出し元に適した振る舞いをすること 」。
Wikipedia「ポリモーフィズム」には以下のように書かれていました。
「プログラミング言語の型システムの性質を表すもので、プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。」
正直、自分には難解でしたが、つまりは「大量の同じ処理を一つのメソッドでまとめて処理する」ようにすることで、短いコードで管理がしやすく、修正に強いコードにすること」が「 ポリモーフィズム 」であると思いました。
ポリモーフィズム(和訳: 多相性)は、オブジェクト指向三大要素(継承, カプセル化, ポリモーフィズム)の1つで、そのなかでも一番理解が難しいとされます。
「ポリモーフィズム的」な考え方の目的についてのまとめが以下です。
【メリット】
ポリモーフィズムを利用しない場合とプログラムと比較して、このようなメリットがあります。
- 記述量が減ることで、修正が加えやすくなる
- コードがきれいにまとまる
- 変更に強い柔軟性があり修正やテストにかかるコストが少ない
【サンプルコード】 ポリモーフィズムを使ってコードの重複を減らす
以下のプログラムは 親クラスに「Animal」,子クラスに「Cat」や「Dog」などのそれぞれ複数の動物クラスを作成し、「鳴き声を表示するメソッド」をそれぞれで出力する ものです。
つまり、以下のような実行結果をするということです。
【Animal.java】親クラス
package about_polymorphism;
abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
// 食べ物の味を出力。
public void letsHear() {
System.out.println(name + "は" + call() + "と鳴く");
}
// 「抽象メソッドの呼び出し」ため、abstract修飾子を使用。
// 具象クラスからのみアクセスするため、protected修飾とする
abstract protected String call();
}
【各種子クラス】
//【Dog.java】
package about_polymorphism;
public class Dog extends Animal {
public Dog() {
super("犬");
}
protected String call() {
return "バウバウ";
}
}
//【Cat.java】
package about_polymorphism;
// 抽象クラスの Animalを 継承
public class Cat extends Animal{
public Cat() {
super("ネコ");
}
protected String call() {
return "にゃーん";
}
}
//【Cow.java】
package about_polymorphism;
public class Cow extends Animal {
public Cow() {
super("牛");
}
protected String call() {
return "ブルルルルル";
}
}
//【Horse.java】
package about_polymorphism;
public class Horse extends Animal {
public Horse() {
super("馬");
}
protected String call() {
return "ヒヒーン";
}
}
【実行結果】
ネコはにゃーんと鳴く
犬はバウバウと鳴く
牛はブルルルルルと鳴く
馬はヒヒーンと鳴く
ポリモーフィズムを使わない場合
ポリモーフィズムな書き方をしないと、以下のように 「行数が多く、同じことを何度も記述」しているコードになっている点に注目です。
【Main.java】
package about_polymorphism;
public class Main {
public static void main(String[] args) {
// ネコクラスの インスタンス 生成
Cat cat = new Cat();
// 鳴き声を表示する メソッドの呼び出し
cat.letsHear();
// 犬クラスの インスタンス 生成
Dog dog = new Dog();
// 鳴き声を表示する メソッドの呼び出し
dog.letsHear();
// 牛クラスの インスタンス 生成
Cow cow = new Cow();
// 鳴き声を表示する メソッドの呼び出し
cow.letsHear();
// 馬クラスの インスタンス 生成
Horse horse = new Horse();
// 鳴き声を表示する メソッドの呼び出し
horse.letsHear();
}
}
ポリモーフィズムな書き方の場合
上記のコードを下記のようなポリモーフィズム的な書き方で スッキリさせることができます。
親クラス 配列 = {new 子クラス(),new 子クラス(),new 子クラス(),new 子クラス()..};
for (親クラス 変数 :配列) {
変数.メソッド();
}
【Main.java】 ポリモーフィズム化
- インスタンス化を一気にまとめて行い配列に格納
- 「定義した子クラス全部で、それぞれメソッドを呼び出す」を拡張for文(for文でも)を用いて行う。
public class Main {
public static void main(String[] args) {
//それぞれのオブジェクトのポインタを格納する配列を用意
// 子クラスのインスタンス化を 配列内に入れてひとくくりに行う
Animal[] animals = { new Cat(), new Dog(), new Cow(),new Horse()};
// 「定義した子クラス全部で、それぞれメソッドを呼び出す」を拡張for文(for文でも)を用いて行う。
for (Animal a : animals) {
a.letsHear();
}
}
}
行数が一気にスッキリしました。
このコードの良いところはスッキリしているだけでなく、「修正に強い」というのも強みです。仮にここに新しく子クラスを追加することになったとしても
- 動物クラスの配列に追加分のインスタンスを書くだけなので行数自体は増えない
- 中心的なソースをいじることなく修正することなく修正が可能
コードがきれいにまとまり、修正が加えやすく、変更に強い柔軟性があり、修正やテストにかかるコストが少ないという、いわゆる「良いコード」を実現しました。
【まとめ】
ポリモーフィズムなプログラムというのは、結果的に DRYの原則(同じことを二度書かない)に従ったプログラムとも言えるかもしれません。