注目キーワード
  1. プログラミング
  2. C#

【C#】ポリモーフィズムについて

C#

はじめに

こうちゃ
こんにちは、こうちゃです。

オブジェクト指向の重要な概念として、ポリモーフィズム (多態性) というものがあります。

これまでみてきた

  • abstract
  • virtual
  • interface

はすべて ポリモーフィズムを実現するための仕組み になります。

今回は、ポリモーフィズムについて 説明していきます。

abstract・virtual・interface をまとめた記事は以下になります。
関連記事

はじめに こうちゃ こんにちは、こうちゃです。 これまで、abstract・virtual・interface について説明してきました。 しかし、クラス設計をしていると、これら3つの違いがわからなくなってくるこ[…]

  • ポリモーフィズムとはなにか
  • abstract・virtual・interface とポリモーフィズムの関係
  • クラスを作成したい方
  • オブジェクト指向に興味のある方
こうちゃ
それでは、やっていきましょう!

ポリモーフィズムとは

ポリモーフィズムは、ひとことで表すと 同じ呼び出し方で動作が異なる仕組み になります。
例えば「Attack」メソッドを呼び出しても、インスタンス (実体) によって「通常攻撃」や「強力攻撃」など実際の動作は異なる性質のことを指します。

ポリモーフィズムについて、1つ例をみていきましょう。
Enemy enemy1 = new Boss();
Enemy enemy2 = new Mob();
enemy1.Attack();
enemy2.Attack();

この場合、

  • 型:Enemy
  • 実体:Boss、Mob

です。

enemy1、enemy2 インスタンスは、外見的には「Enemy」クラスになります。
ですが内面はそれぞれ「Boss」「Mob」クラスという状態です。
結果的に、

  • 見た目は「Enemy クラスの Attack メソッドが呼び出された」
  • 実際の動作は「Boss クラス、および Mob クラスの Attack メソッドが呼び出された」

という状態です。
このように、見た目は同じだが、実際の挙動は異なる ものがポリモーフィズムです。

ポリモーフィズムの重要性

冒頭で、ポリモーフィズムはオブジェクト指向において重要な概念だという話をしました。
では、どのように重要なのでしょうか。

重要性①:コードを共通化できる

1つ目は、コードが共通化できる点です。

List<Enemy> enemies = new List<Enemy>();

上記の「enemies」には、「Enemy」クラスを継承しているインスタンスはすべて追加可能です。
例えば「Mob」「Boss」「Dragon」クラスなどのインスタンスが追加できます。

foreach (var enemy in enemies)
{
    enemy.Attack();
}

上記のように、「enemies」をループして、各要素に対して「Attack」メソッドを呼ぶことが可能になります。
先ほども言ったように、「enemies」には「Enemy」クラスを継承しているインスタンスはすべて追加できます。
そのため、「enemies」をループするだけで、実体を気にせず「Attack」メソッドを呼ぶことができます。

重要性②:条件分岐が不要になる

重要性①が可能になることにより、条件分岐が不要になり、コードがわかりやすくなります。
仮にポリモーフィズムを使わない場合、以下のような条件分岐が必要になります。

if (enemy is Mob) ...
if (enemy is Boss) ...

「Attack」メソッドのみならこれでも良いかもしれません。
しかし「敵キャラ」に共通する機能が増えるほど、この書き方はしんどくなっていきます。

重要性③:拡張に強い

「Enemy」クラスを継承した新たなクラスが作成された場合でも、以下の1行を追加するだけで良くなります。

enemies.Add(new NewEnemy());

重要性①のように、「enemies」をループさせてメソッドを呼んでいるため、新しいクラスのインスタンスを「enemies」に追加するだけで期待する動作をしてくれます。

abstract・virtual・interface とポリモーフィズム

abstract・virtual・interface とポリモーフィズムの関係についてみていきましょう。

abstract とポリモーフィズム

役割

必ず動作が異なる ことを保証する

abstract class Enemy
{
    public abstract void Attack();
}
class Boss : Enemy
{
    public override void Attack()
    {
        Console.WriteLine("強力な攻撃!");
    }
}
class Mob : Enemy
{
    public override void Attack()
    {
        Console.WriteLine("通常攻撃");
    }
}

ポイント

  • すべてのクラスで必ず「Attack」メソッドを実装
  • 必ず動作が異なる

ポリモーフィズムを強制する

virtual とポリモーフィズム

役割

必要に応じて異なる動作 にできる

class Enemy
{
    public virtual void Attack()
    {
        Console.WriteLine("通常攻撃");
    }
}
class Boss : Enemy
{
    public override void Attack()
    {
        Console.WriteLine("強力な攻撃!");
    }
}

ポイント

  • override しなければ親クラスと同じ動作
  • override すれば異なる動作

柔軟なポリモーフィズム

interface とポリモーフィズム

役割

共通の呼び出し方法 を定義できる

interface IAttack
{
    void Attack();
}
class Enemy : IAttack
{
    public void Attack()
    {
        Console.WriteLine("攻撃");
    }
}

class Player : IAttack
{
    public void Attack()
    {
        Console.WriteLine("プレイヤー攻撃");
    }
}
List<IAttack> attackers = new List<IAttack>
{
    new Enemy(),
    new Player()
};

foreach (var attacker in attackers)
{
    attacker.Attack();
}

ポイント

  • クラスが異なっていても同じように呼び出すことができる

型を超えたポリモーフィズム

各概念とポリモーフィズムの関係まとめ

概念 ポリモーフィズムとの関係
abstract 動作の違いを強制する
virtual 動作の違いを任意にする
interface 呼び出し方法を統一する

まとめ

ポリモーフィズムは 同じ呼び出し方で異なる動作をする仕組み になります。

そして、

  • abstract → 強制的に異なる動作を作る
  • virtual → 柔軟に異なる動作を作る
  • interface → 共通の呼び出し方を作る

という違いがそれぞれありました。

重要なのは、abstract・virtual・interface はどれもポリモーフィズムを実現する方法 ということです。

さいごに

今回はポリモーフィズムについて説明しました。

「ポリモーフィズム」という用語が出てきましたが、内容としてはこれまでの記事で記載してきたもののまとめだったと思います。
abstract・virtual・interface をそれぞれ説明した時点で、実際にはポリモーフィズムを使っていたということを理解していただけたでしょうか。
新しい用語が出ると身構えてしまいますが、もうすでに知っている内容だと安心しますよね。

ここまでくると、クラス (オブジェクト指向) の基本的な部分は触れたことになります。
もちろんもっと奥は深いですが、これまでの内容から発展していくに過ぎません。
どんどんマニアックになっていきますね。(笑)

以降のクラスに関わる記事は、個人的に有用だった内容を取り扱っていきます!
今回はここまで♪

こうちゃ
それではみなさま、お疲れ様でした!
楽しいプログラミングライフを!
最新情報をチェックしよう!