接口

用一段代码处理好几种东西,以及给类和给组件分别该用什么。

更新于 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 没法序列化接口字段。写成接口类型,这个字段根本不会出现在 Inspector 里。

所以当你想共享的东西是一个 behaviour 时,用抽象基类:

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;      // 推拉门和平开门都可以拖到这里

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

字段会出现在 Inspector 里,两种门都收,door.Open() 调用的是对的那一个。基类还能带上共享的状态和共享的代码,这是接口做不到的。

在普通的 Unity 里,出于同样的原因也是这么做的。

怎么选

你想要
让代码里创建的几个类遵守同一个约定 接口
让 GameObject 上的几个 behaviour 遵守同一个约定 抽象基类
共享状态或共享方法实现 抽象基类

基类本身也可以实现接口,所以确实需要的时候,一个 behaviour 两者兼得。

出了点问题 重新加载