【C#】WPFアプリケーション入門 #12 ポリモーフィズムとインターフェース

はじめに

オブジェクト指向 (#10) でポリモーフィズムについて扱いました。ポリモーフィズムを意識すると、同じメソッドなのにクラスが違うと処理内容が変わるような処理ができます。つまり、操作名を共通化できます。

お品書き

今回扱う内容です。

  1. ポリモーフィズムの考え方
  2. インターフェース
  3. 実装

1. ポリモーフィズムの考え方

ポリモーフィズムは多様化ともいい、おおまかな操作を共通にして使いまわしができるようにする考え方です。どういうことかというと、

class Main
{
    private void Button_Mountain(object sender, RoutedEventArgs e)
    {
        Go();
    }

    private void Button_Sea(object sender, RoutedEventArgs e)
    {
        Go();
    }

    private void Button_House(object sender, RoutedEventArgs e)
    {
        Go();
    }

    void Go ()
    {
        //お出かけの処理は1つで十分
    }
}

こうしたいわけです。山も海も家も Go() というメソッドを呼び出したいですが、このままではうまくいきません。それは、場所の違いです。 いくら出かけるといっても山は山のデータ、海は海のデータがあるので複数のメソッドを作る必要があります。

class Main
{
    private void Button_Mountain(object sender, RoutedEventArgs e)
    {
        Go_Mountain();
    }

    private void Button_Sea(object sender, RoutedEventArgs e)
    {
        Go_Sea();
    }

    private void Button_House(object sender, RoutedEventArgs e)
    {
        Go_House();
    }

    void Go_Mountain ()
    {
        // 山に関する処理
    }

    void Go_Sea ()
    {
        // 海に関する処理
    }

    void Go_House ()
    {
        // 家に関する処理
    }
}

これではメソッドは一度しか呼び出されず、再利用性どころか多様性がありません。つまり、山には山のメソッド、海には海のメソッド、家には家のメソッドというように1対1の関係になっており、それ専用になってしまいます。そうならないよう、今回はインターフェースを用います。

2. インターフェース

共通のメソッドを宣言しておくことができる構文です。ただし、インターフェースではメソッドを宣言できますが、メソッドの内容を定義することはできません。
メソッドの内容は各クラスで定義できます。実際に使用するためには5つの段階が必要です。

  1. 各クラスで共通名のメソッドを用意し、そこに処理内容を定義する。
  2. インターフェースを作成して 1 で定義したメソッド名を記述する。
  3. インターフェースを各クラス名でインスタンス化する。
  4. インターフェース名を引数にできるようなメソッドを定義する。
  5. 4のメソッドを呼び出したいとき、引数に処理させたいクラス名を指定する。

これをもとにしてインターフェースを使ってみます。

3. 実装

まずは各クラスとインターフェースを作り、インターフェースを継承と同じようにくっつけます。

public class Mountain : Place
{
    public string Go()
    {
        return "山へお出かけ";
    }
}

public class Sea : Place
{
    public string Go()
    {
        return "海へお出かけ";
    }
}

public class House : Place
{
    public string Go()
    {
        return "家でゴロゴロ";
    }
}

続いて、インターフェース Place を実装します。今回、メソッド名はGo()なのでGoメソッドを作成します。 あとはインターフェースをクラスでインスタンスを生成すれば使うことができます。

Place mountain = new Mountain();
Place sea = new Sea();
Place house = new House();

public interface Place
{
    string Go();
}

これでインターフェースを実装できました。あとは使うだけです。

public void Go(Place place)
{
    MessageBox.Show($"{place.Go().ToString()} + へ行く");
}

private void Button_Mountain(object sender, RoutedEventArgs e)
{
    Go(mountain); //Goメソッドにmountainクラスを渡す
}

このようにすることで、Goメソッドに呼び出したい(使用したい)クラスを引数として入力し、個々のデータを得られます。図にするとこんな感じです。 f:id:takunology:20191025235629p:plain

例えば、"山へ行く"という文字列を表示したい場合は Goメソッドの引数にMountainクラスを代入すれば、そのクラスで定義したGoメソッドが呼び出されます。そのメソッドの返り値として、"山へ行く"が得られます。 f:id:takunology:20191026001009p:plain

実行するとこのような感じになります。 f:id:takunology:20191026002309p:plain

おわりに

インターフェースを使うことでメソッド1つで3つのクラスを操作できました。これだけではクラスを継承するのとあまり変わらないので、恩恵を感じられないですね。ただ、プロジェクトが複雑になるほど効果を発揮しそうですね!

今回作成したコード

参考にどうぞ。

github.com

参考にしたサイト

ありがとうございます。詳しい説明はこちらを参考にしたほうが分かりやすいです。 ufcpp.net