ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

C# - インターフェース(interface)

初めに

 インターフェースとは、直訳では「境界面」を意味し、オブジェクト指向プログラミングの世界においては、クラスが実装すべき規約を定め、クラス設計者とクラス利用者の間の仲介役を担うものです。IEnumerable や IEnumerator などよく見るインターフェースも多いです。本記事では、C# におけるインターフェースについて、まとめます。



インターフェース(interface)

インターフェースとは

 インターフェースとは、直訳では「境界面」を意味します。
 オブジェクト指向プログラミングの世界においては、インターフェースとは、

クラスが実装すべき規約を定めるもの。クラス外部からみた規約だけを定めるもの。

になります。

C# におけるインターフェース

 インターフェースとは、クラスが実装すべき規約を定めるものでした。C# において、この規約とは関数の引数や返り値の定義のことです。

 C#には、抽象メソッドと呼ばれる規約(引数や返り値)のみ定義した関数と抽象クラス(抽象メソッドが定義できるクラス)があります。

fineworks-fine.hatenablog.com

 つまり、C# において、インターフェースとは、

抽象メソッドのみをもつクラスのようなもの

になります。

 抽象クラスと似ていますが、以下のような違いがあります。

  • メンバー変数(フィールド)を持つことが出来ない。
  • static メソッドを持つことが出来ない。
  • 宣言したメソッド・プロパティはすべてpublic abstractになる。
  • 1つのクラスが複数のインターフェースを実装(多重継承)できる

 抽象クラスは、抽象メソッド以外の関数を定義できたり、変数の定義ができたりしました。また、多重継承はできませんでした。

インターフェースの定義、実装

 インターフェースは次のように定義されます。

interface インターフェース名
{
メソッド・プロパティの宣言
}

 また、インターフェースの実装はクラスの継承と同じように行います。

class クラス名 : インターフェース名
{
クラスの定義
}

(例)

using System;
using UnityEngine;

public class InterfaceSample : MonoBehaviour
{
    void Start()
    {
        IPoint p = new Point(2, 3);
        PrintPoint(p);
    }

    static void PrintPoint(IPoint p)
    {
        Debug.Log($"x={p.X}, y={p.Y}");
    }
}

//インターフェースの定義
interface IPoint
{
    //プロパティの定義
    int X { get; set; }

    int Y { get; set; }

    double Distance { get; }
}

//IPointというインターフェースを実装
class Point : IPoint
{
    // Constructor:
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    // Property implementation:
    public int X { get; set; }

    public int Y { get; set; }

    // Property implementation
    public double Distance =>
       Math.Sqrt(X * X + Y * Y);
}

※Unity上で動作するようにしています。通常のC#の場合は、少し書きかえてください。

標準クラスライブラリ中のインターフェース

 .NET Framework の標準クラスライブラリは、いくつかのインターフェースを標準で用意しています。

 例えば、次のような機能のインターフェースがあります。

インターフェース 機能 名前空間
IComparable 順序比較ができるものを表す System
IEnumerable 要素の列挙ができる System.Collections.Generic
IDictionary 文字列キーを使用して、値の検索ができる System.Collections.Generic

 標準ライブラリ中のインターフェースは I から始まります。System や System.Collections.Generic など名前空間ごとにどのようなインターフェースがあるのか、Microsoft のドキュメントにまとめてあるので、詳しくはそちらを参照してください。

learn.microsoft.com
learn.microsoft.com

インターフェースのメリット

 インターフェースのメリットはいくつかあります。本記事では、2つ紹介します。

  1. 関数をクラスごとに別の処理をさせることができる
  2. インターフェースごとにどのような機能をもっているのか、保証されるので、余計な事を気にしなくてよい。

1. 関数をクラスごとに別の処理をさせることができる
 関数をクラスごとに別の処理をさせることができることのメリットは、ポリモーフィズムの考え方に関わります。

 例えば、Animal という基底クラスから Dog という派生クラスと Cat という派生クラスを作ったとします。「鳴き声を取得する」など、ある関数を呼び出したとき、Dog と Cat では別の処理がしたい。しかし、鳴き声を返すというルールは守ってほしい。このような場合に、関数の規則だけ決めておいて、クラスごとに処理を記述できることはメリットになります。

fineworks-fine.hatenablog.com

2. インターフェースごとにどのような機能をもっているのか、保証されるので、余計な事を気にしなくてよい。

 Linq の Where 関数を例に説明します。

 Linq の Where 関数は条件を満たす要素を抽出できる関数になります。 IEnumerable を引数、戻り値にもちます。

配列.Where(要素 => 抽出条件);
Where(IEnumerable, Func)

(例)

//listの定義
List<string> fruits = new List<string> { "apple", "passionfruit", "banana", "mango", "orange", "blueberry", "grape", "strawberry" };

//Where関数を使う
IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);


 IEnumerable は要素の列挙ができるインターフェースです。引数や戻り値を IEnumerable にすることで、list なのか配列なのかを指定する必要がなくなります。IEnumerable を使うことで、引数には list や配列を代入することができます。また、戻り値も IEnumerable になるため、ToList() 関数を使って list に変換したり、ToArray() 関数を使って配列に変換することができます。

最後に

  • インターフェースはクラスが実装すべき規約を定めるもの。C#では、抽象メソッドのみをもつクラスのようなものである。
  • インターフェースの実装は、クラスの継承と同じように行う
  • .NET Framework の標準クラスライブラリにいくつかインターフェースが用意されている