インターフェース

いくつもの種類のものを同じコードで扱う方法と、クラス向け・コンポーネント向けの使い分け。

更新日 2026-09-07

インターフェースは「何であるか」ではなく「何ができるか」の約束です。約束に向けてコードを書けば、その約束を守るものすべてで動きます。

public interface IShape
{
    int Area();
}

public class Square : IShape
{
    public int side;

    public int Area()
    {
        return side * side;
    }
}

public class Rect : IShape
{
    public int width;
    public int height;

    public int Area()
    {
        return width * height;
    }
}

IShape を持っている側は、それがどの種類かを知らないまま面積を訊けます。答えは実際にそこにあるクラスから返ってきます。

IShape shape = square ? (IShape)new Square() : new Rect();

int area = shape.Area();

この決定はワールドが動いている最中に行えます。これが日常的な使い方であり、インターフェースが働く場所です。ひとつのコードで、何種類ものものを扱えます。

効いてくる場面

型を表すフィールドに対して長い if を書くことになりそうな場所すべてです。

  • インベントリのアイテム。使ったときの動きがそれぞれ違う
  • クエストの手順。完了の判定がそれぞれ違う
  • プレイヤーへの効果。ルールがそれぞれ違う
  • 武器。撃つという意味が武器ごとに違う

インターフェースで書いておけば、新しい種類のアイテムを足すのはクラスをひとつ足すことです。IItem を使う側は何も変わりません。

コンポーネントは別: 基底クラスを使う

インターフェースはコードの中で作るクラスのためのものです。コンポーネントは事情が違います。GameObject にドラッグして Unity にその参照を保存させる必要があり、Unity はインターフェースのフィールドを保存できないからです。インターフェース型にすると、そのフィールドはインスペクタに現れません。

なので共有したいものがビヘイビアなら、抽象基底クラスを使います。

public abstract class Door : UdoniteBehaviour
{
    public abstract void Open();
}

public class SlidingDoor : Door
{
    public override void Open() { /* ... */ }
}

public class SwingingDoor : Door
{
    public override void Open() { /* ... */ }
}

スイッチはフィールドひとつでどちらのドアにも対応できます。

public class Switch : UdoniteBehaviour
{
    public Door door;      // SlidingDoor でも SwingingDoor でもここにドラッグできる

    public override void Interact()
    {
        door.Open();
    }
}

フィールドはインスペクタに現れ、どちらのドアも受け取り、door.Open() は正しいほうを動かします。基底クラスは共有の状態や共有のコードも持てます。インターフェースにはできないことです。

これは普通の Unity でも同じ理由で同じようにする話です。

使い分け

したいこと 使うもの
コードの中で作る複数のクラスに同じ約束を持たせる インターフェース
GameObject 上の複数のビヘイビアに同じ約束を持たせる 抽象基底クラス
状態やメソッドの中身を共有する 抽象基底クラス

基底クラスがインターフェースを実装することもできるので、本当に必要なときはビヘイビアが両方を兼ねられます。

問題が発生しました 再読み込み