前回は「オーバーライド(親の処理を子で上書きする)」をやりました。

今回は、そのオーバーライドが本領を発揮する仕組み、ポリモーフィズムです。名前は難しそうですが、考え方はシンプルで、とても強力です。

ポリモーフィズムとは、同じ命令を出しても、相手によって違う動きをすることです。

名前の意味

「ポリモーフィズム」は、「いろいろな(ポリ)形(モーフ)」という意味です。日本語では「多態性(たたいせい)」とも言います。

ひとことで言うと、「同じ呼び方なのに、中身が違う」こと。前回のオーバーライドで、すでにその入り口は見ています。

taro.Greet();     // 会社員の山田です
hanako.Greet();   // 学生の田中です

同じ Greet() なのに、会社員と学生で違う動き。これがポリモーフィズムの基本です。今回は、これをもっと強力に使います。

まとめて扱えるのが、すごいところ

前回やった継承を思い出してください。会社員も学生も「Person(人)の一種」でした。

だから、まとめて Person として扱えるんです。

List<Person> people = new List<Person>();

people.Add(new Employee { Name = "山田" });   // 会社員を
people.Add(new Student { Name = "田中" });    // 学生を
people.Add(new Employee { Name = "佐藤" });   // また会社員を

会社員も学生も、ぜんぶ「Person のリスト」に入れられます。中身は別の種類なのに、「人」としてまとめられる。継承のおかげです。

ここからが、ポリモーフィズム

では、このリストの全員に、あいさつさせてみます。

foreach (Person p in people)
{
    p.Greet();
}

結果は、こうなります。

会社員の山田です
学生の田中です
会社員の佐藤です

ここが、不思議で、すごいところです。

p は「Person」として扱っているのに、実物が会社員なら会社員のあいさつ、学生なら学生のあいさつになりました。

同じ p.Greet() という1つの命令。でも、実物の種類に応じて、自動的に正しい動きをしてくれる。これがポリモーフィズムです。

なぜ、これが強力なのか

このコードを、もう一度見てください。

foreach (Person p in people)
{
    p.Greet();   // 会社員か学生か、気にしていない
}

このループは、相手が会社員か学生かを、いっさい気にしていません。ただ「Person として、Greet を呼ぶ」だけ。あとは、それぞれの実物が、自分に合った動きをしてくれます。

これの何が嬉しいか。たとえば、新しく「公務員」クラスを追加したとします。

class Officer : Person
{
    public override void Greet() { Console.WriteLine("公務員の" + Name + "です"); }
}

このとき、さっきのループは、1文字も書き換えなくていいんです。

people.Add(new Officer { Name = "鈴木" });

foreach (Person p in people)
{
    p.Greet();   // このコードはそのまま。公務員も正しくあいさつする
}

新しい種類が増えても、それを使う側(ループ)は変えなくていい。変更に、とても強い。これがポリモーフィズムの、本当の威力です。

たとえるなら

ポリモーフィズムは、リモコンの「再生ボタン」のようなものです。

DVDでも、音楽プレーヤーでも、動画アプリでも、「再生」ボタンを押せば、それぞれが正しく再生します。押す側は、中身の違いを知らなくていい。「再生して」と言うだけ。

p.Greet() も同じ。「あいさつして」と言うだけで、会社員も学生も公務員も、それぞれ正しくあいさつする。指示する側は、中身を気にしなくていい。この「気にしなくていい」が、プログラムをシンプルに保つ秘訣です。

つまずきポイント

ポリモーフィズムは、これまでの積み重ねの上に成り立っています。一度で完全に分からなくても、当然です。

成り立つために必要なのは、

  • 継承(第23回)… 会社員も学生も Person の一種
  • オーバーライド(第24回)… それぞれが Greet を上書き

この2つが土台です。もし「分かりにくいな」と感じたら、前の2回に戻ってみてください。継承とオーバーライドがしっかり分かると、ポリモーフィズムは自然と腑に落ちます。

まとめ

ポリモーフィズムは、同じ命令で、相手によって違う動きをする仕組み。

foreach (Person p in people)
{
    p.Greet();   // 実物の種類に応じて、自動で正しく動く
}
  • 違う種類を、共通の親(Person)としてまとめて扱える
  • 同じ命令でも、実物に合った動きをする
  • 新しい種類が増えても、使う側を変えなくていい
  • 継承とオーバーライドの上に成り立つ

次回は、オブジェクト指向編の最後。「形だけ決めて、中身は任せる」抽象クラスとインターフェース です。