【C#】Interfaceの使いどころは配列ぶん回しのポリモーフィズムで理解出来る!

この記事は約 6 分で読めます。

みなさんこんにちは!ひろぽんです!

オブジェクト指向の3大要素の一つであるポリモーフィズムについて書いていきたいと思います!

オブジェクト指向を学び始めた初心者が必ず躓くといって良いほど結構難しい概念なのですが、オブジェクト指向を学ぶ上で避けては通れません!

またinterfaceの存在は知っていても、どのように使うのがいいのか?おいしさは何なのか?というのが分からないという人も多いと思います。

私はC#でのinterfaceおいしさはこのポリモーフィズムに全て集約されているといっても過言ではないと思っていますので、今回はinterfaceとポリモーフィズムの使いどころの例に配列ぶん回しをして解説していきたいと思います。

まずはInterfaceを定義

namespace InterfaceExample
{
    public interface ISayHello
    {
        void Say();
    }
}

めっちゃシンプルな感じで、Interfaceを宣言しました。

このInterfaceを継承するクラスは絶対にSay()という関数を実装しないといけません。

Interfaceを継承したクラスを定義

using System;

namespace InterfaceExample
{
    public class CSharpHello : ISayHello
    {
        public void Say()
        {
            Console.WriteLine("Hello CSharp");
        }
    }
}

クラス一つ目はHelloCSharpとコンソールに出すだけのクラスです。

using System;

namespace InterfaceExample
{
    public class VBnetHello : ISayHello
    {
        public void Say()
        {
            Console.WriteLine("-----------------------");
            Console.WriteLine("Hello Vb.net");
        }
    }
}

二つ目のクラスはHello VB.netとコンソールに出しますが、その一行上に—-で線を引きます。

Interfaceの配列を定義

で上記二つのクラスを配列に入れてぶん回したいのですが、ISayHelloというインターフェースを実装しているので、ISayHelloの型の配列を宣言します。

namespace InterfaceExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var helloList = new ISayHello[]
            {
                new CSharpHello(), new VBnetHello(),
            };
        }
    }
}

配列をぶん回して実行

で上記の関数をぶん回します。

    class Program
    {
        static void Main(string[] args)
        {
            var helloList = new ISayHello[]
            {
                new CSharpHello(), new VBnetHello(),
            };

            foreach (var sayHello in helloList)
            {
                sayHello.Say();
            }

            Console.ReadLine();
        }
    }

Interfaceの関数を実行しているのに結果が違う

するとISayHelloのInterfaceのSayを実行しているのに、違う結果に出ました。

これはnewしたインスタンスの型が違うから、interfaceを通じてnewしたインスタンスの中身を見ているのですね!

例えばこんな使い方もできます。

自由にHelloというクラスを作ってみる

using System;

namespace InterfaceExample
{
    public class FreeHello : ISayHello
    {
        private string _helloItem;
        public FreeHello(string helloItem)
        {
            _helloItem = helloItem;
        }

        public void Say()
        {
            Console.WriteLine($@"Hello {_helloItem}");
        }
    }
}

例えばこんな感じでコンストラクタの引数にHello ○○の○○の文言を取るものを追加したとします。

しかしこのFreeHelloはISayHelloを継承しているので、問題なく配列に追加できます。

namespace InterfaceExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var helloList = new ISayHello[]
            {
                new CSharpHello()
                , new VBnetHello()
                , new FreeHello("Python")
                , new FreeHello("JavaScript"),  
            };

            foreach (var sayHello in helloList)
            {
                sayHello.Say();
            }

            Console.ReadLine();
        }
    }
}

こんな感じでね!

で実行すると!

こんな感じで文言が追加されています!

ISayHelloのInterfaceを引数に取る関数を作ってみる

でこれだけだとおいしさが半減すると思うのでInterfaceを下記のように修正しましょう。

namespace InterfaceExample
{
    public interface IGetHello
    {
        string GetHello();
    }
}

さっきのHello CSharpとかの文言を戻り値として返すようにします。

で上記で宣言したクラスを下記のように修正します。

namespace InterfaceExample
{
    public class CSharpHello : IGetHello
    {
        public string GetHello()
        {
            return "Hello CSharp";
        }
    }
}
namespace InterfaceExample
{
    public class VBnetHello : IGetHello
    {
        public string GetHello()
        {
            return "Hello Vb.net";
        }
    }
}
namespace InterfaceExample
{
    public class FreeHello : IGetHello
    {
        private string _helloItem;
        public FreeHello(string helloItem)
        {
            _helloItem = helloItem;
        }

        public string GetHello()
        {
            return $@"Hello {_helloItem}";
        }
    }
}

で最後にIGetHelloを引数にとってConsoleに表示する関数を作ります。

namespace InterfaceExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var helloList = new IGetHello[]
            {
                new CSharpHello()
                , new VBnetHello()
                , new FreeHello("Python")
                , new FreeHello("JavaScript"),  
            };

            helloList.ToList().ForEach(ShowConsole);
            Console.ReadLine();
        }

        static void ShowConsole(IGetHello sayHello)
        {
            Console.WriteLine(sayHello.GetHello());

        }
    }
}

このようにすると結果は下記になります。

ポリモーフィズムとはInterfaceありき

で最後にまとめですが、Interfaceは上記のように実行する関数は同じだけれども、中身の実装を変えたいときに効果を発揮します。

今回のは一例ですが、下記のような使い方もできます。

Sqlを実行する関数を作ったとして引数はISqlQueryBuilderというGetquery()という関数を持ったインターフェースを用意。

上記インターフェースを継承した下記のクラスを用意する。

  • DeleteQueryBuilder
  • InsertQueryBuilder
  • UpdateQueryBuilder
  • SelectQueryBuilder

ここまですれば中身の実装をそれぞれ別々のクエリを発行するようにして、Sqlを実行する関数に投げれば中で勝手に処理をしてくれます。

これがポリモーフィズムです!!!

今回のコードはサンプルでGithubに上げています!

下記GITHUBリポジトリに今回のソースコードを上げています!

https://github.com/adaman3568/blog-source-demo

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA