【c#】通俗解释C#中的 “接口”

需求:
公司有两个人分别写了"小狗类"和"小猫类",两个类里都已经写好了小狗和小猫喜欢的食物的方法,主程让你写一个类来输出它们各自喜欢的食物。

首先,我们先来看一看 A 程序员写的"小狗类",里面有个 LikeFood 方法,如下代码所示:

// A程序员写的小狗类
class Dog
{
    public void LikeFood()
    {
        Debug.Log("我是小狗,我喜欢吃肉");
    }
}

B 程序员写的"小猫类",里面也有一个 LikeFood 方法,如下代码所示

// B程序员写的小猫类
class Cat
{
    public void LikeFood()
    {
        Debug.Log("我是小猫,我喜欢吃鱼");
    }
}

你按照需求写了一个动物园类 Zoo,代码如下所示:

//动物园类
class Zoo
{
    public void Show(Dog dog)
    {
        dog.LikeFood();
    }

    public void Show(Cat cat)
    {
        cat.LikeFood();
    }
}

在 Start 方法里,并实现了小狗小猫喜欢的食物的功能,代码如下:

    void Start()
    {
        Zoo zoo=new Zoo();
        zoo.Show(new Dog());
        zoo.Show(new Cat());
    }

运行u3d,输出如下图所示:
在这里插入图片描述
主程交代的功能完美实现了,这一切工作良好,但好景不长,公司又需要给动物园增加一个猴子,让C程序员去写这个 Monkey 类,并能输出它喜欢的食物。

C 程序员写的"小猴子类",里面同样也有一个 LikeFood 方法,如下代码所示

// C程序员写的小猴子类
class Monkey
{
    public void LikeFood()
    {
        Debug.Log("我是小猴子,我喜欢吃香蕉");
    }
}

于是你的 Zoo 类就变成了这样,仅仅多了一个重载方法:

//动物园类
class Zoo
{
    public void Show(Dog dog)
    {
        dog.LikeFood();
    }

    public void Show(Cat cat)
    {
        cat.LikeFood();
    }

    public void Show(Monkey monkey)
    {
        monkey.LikeFood();
    }
}

然后你在 Start 方法里也做了稍微改动,代码如下所示:

    void Start()
    {
        Zoo zoo=new Zoo();
        zoo.Show(new Dog());
        zoo.Show(new Cat());
        zoo.Show(new Monkey());
    }

也正确输出了结果,你不禁暗暗得意,一个变化而已,我只需要再Zoo类里增加一个重载方法就好了。

但如果后面还有更多动物需要你输出它们喜欢的食物,你的Zoo类都要修改,这对你来说不是一件好事。”

于是你仔细观察 Zoo 类,发现不变的是 Show 方法,变化的是 Show 方法是参数。因为每个动物都不一样,所以参数也就不一样。所以原来就需要重载多个方法。

如果有一个类,能接收所有动物,那不就解决了?没错,于是你想到了定义一个父类叫 Animal ,里面有个 LikeFood 方法,让所有动物类去继承 Animal 类。

最后你的 Animal 类代码如下:

class Animal
{
    public virtual void LikeFood()
    {
        Debug.Log("我是Animal类");
    }
}

:原文里并没有 virtual 关键字,参考的时候我也没有看出来有什么问题,我自己打印的时候输出的全部是“我是Animal类”,才看出来有问题(每个子类的对象都只是实现了父类的方法,并不是自己的方法)

Zoo 类代码如下:

//动物园类
class Zoo
{
    public void Show(Animal animal)
    {
        animal.LikeFood();
    }
}

你告诉A.B.C程序员,让它们写的动物类都去继承Animal(这里我让每个子类的 LikeFood 方法都重写了父类的 LikeFood 方法),并且里面有个输出动物喜欢食物的方法,三人代码如下:

class Dog:Animal
{
    public override void LikeFood()
    {
        Debug.Log("我是小狗,我喜欢吃肉");
    }
}

class Cat:Animal
{
    public override void LikeFood()
    {
        Debug.Log("我是小猫,我喜欢吃鱼");
    }
}

class Monkey:Animal
{
    public override void LikeFood()
    {
        Debug.Log("我是小猴子,我喜欢吃香蕉");
    }
}

运行也一切良好,不管以后还有什么类,只要让需要添加的动物类,继承Animal,并有个l LkeFood 方法,那么你无需修改 Zoo 类,只需要在 Start 方法里传入动物类的实例就能正常工作。

你大赞你聪明绝顶,这样一来,你的 Zoo 类根本不需要改变了。

有一天,公司新来一个程序员D,主程让D写个兔子类,你告诉D,你写的 Rabbit 类必须继承Animal,并且有一个它喜欢的食物的方法。

D按照你要求的,写的兔子类如下:

class Rabbit:Animal
{
    public void FavoriteFood()
    {
        Debug.Log("我是兔子,我喜欢吃萝卜");
    }
}

然后你在 Start 方法里又加了一行代码 zoo.Show(new Rabbit());

运行程序后,Raabit 类并没有输出预想的结果,你不得不花了点时间去排查原因,最后你发现这不是什么大问题,因为新来的D虽然写了 Rabbit 类,但里面的方法叫:FavoriteFood()。

因为他并不知道你们之前约定的动物喜欢的食物的函数需要命名为:LikeFood()

但是,为什么会导致这个问题?

那是因为没有一种约束,使得子类继承父类的时候必须实现父类的方法。有没有一个类,能让它的子类必须实现它定义的方法?有,那就是接口。

于是你修改 Animal 类为接口,代码如下:

interface Animal
{
    void LikeFood();
}

A,B,C,D程序员的代码修改如下(此时我把父类的virtual和子类的override关键字已经去掉)

class Dog:Animal
{
    public void LikeFood()
    {
        Debug.Log("我是小狗,我喜欢吃肉");
    }
}

class Cat:Animal
{
    public void LikeFood()
    {
        Debug.Log("我是小猫,我喜欢吃鱼");
    }
}

class Monkey:Animal
{
    public void LikeFood()
    {
        Debug.Log("我是小猴子,我喜欢吃香蕉");
    }
}

class Rabbit:Animal
{
    public void LikeFood()
    {
        Debug.Log("我是兔子,我喜欢吃萝卜");
    }
}

由于 Animal 接口有个 LikeFood() 方法,那么 Rabbit 子类去实现 Animal 接口必须实现LikeFood(),否则程序不能通过。

如果之前我们以接口的形式写了Animal,D程序员继承了Animal类但却写成Favorite的时候,就会报错。如下图所示:
【c#】通俗解释C#中的 “接口”_第1张图片
错误很清楚,不用你事先告诉D程序员需要把方法名写成 LikeFood ,他也会改的。

D改正后代码正常工作,因为Animal是接口,里面有个LikeFood() 方法,以后再添加各种动物进来,只需要实现 Animal 接口,并且也不会出现有的人会因为子类的方法命名问题而导致出错了。

这时你再想,虽然用继承一个普通父类也可以满足要求,但是一个普通父类根本没有约束力
而用了接口就不一样了,子类必须实现父类的所有方法,因为 Zoo 类里调用的是LikeFood(),由于子类必须实现父类,那么所有子类都会有 LikeFood(),你根本不用担心子类有没有这个方法。

所以接口能在多人协作下,定义一系列方法,让子类必须存在接口定义的类,防止在另外的类里调用一个人写的接口的子类时,找不到方法的问题。


结束语

如果这篇博客有幸帮到了您,欢迎点击下方链接,和更多志同道合的伙伴一起交流,一起进步。

Web开发者俱乐部

你可能感兴趣的:(C#,C#)