[C#] interface接口学习

学习链接:Untiy Learn

一. 什么是interface

interface即接口,接口定义了所有类继承接口时应遵循的语法合同。
接口定义了语法合同“是什么”部分,派生类定义了语法合同“怎么做”部分。
接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。派生类则要对成员进行定义。接口提供了派生类应遵循的标准结构。

简单举个例子来说(瞎说),接口就像是老板,继承接口的类就像是老板底下的员工。比如游戏老板只需要提出:"我想做个RPG游戏,策划人员给我去写策划案,程序人员之后写个demo,测试人员准备后续去测试demo”,不需要去自己动手做(声明)。而各个员工们则必须完成老板说的事情,策划人员写完整具体的策划方案,程序人员实现具体的程序代码,测试人员对程序功能部分进行一个个具体测试(定义)。

二. 为什么要用interface

答:多态性的体现
举个例子:一款游戏,有玩家和敌人两种角色,这两种角色都必须有血量属性攻击方法。正常情况下可以通过两个脚本EnemyPlayer中都定义血量和攻击方法去实现,稍微再重构一下的话可以通过定义一个抽象基类例如Character来对血量和攻击方法去抽象声明实现(也是一个相对不错的选择)。但如果是针对必须实现血量和攻击方法,就要用到接口来声明,进而由Enemy和Player去继承该接口。
PS: 当然这里介绍接口,跟抽象类还是有一定的区别,以后有机会再写一篇对两者的差异对比。

三. 如何定义一个接口

定义接口要用到关键字interface声明,接口默认声明是public。这边以创建一个可伤害的脚本为例,接口名通常以I字母开头,其中有属性Health和方法Damage,如下所示:

public interface IDamagable
{
    int Health { get; set; }

    void Damage(int damageAmount);
}

那有人可能会问为什么定义属性,而不能是字段呢,直接int health不行么?
接口明确规定了不能定义字段,这也是其跟抽象类的一个区别,主要原因是接口是描述规则的,无法被实例化,而定义字段就必须要分配内存实例化。
对于Damage方法来说,只需要声明这个方法,不需要具体去实现,应由继承接口的类去实现。

四. 使用接口

在Unity中创建了两个GameObject分别命名为Enemy和Player,两个物体上分别添加了脚本Enemy和Player。
这里定义了两个类Player和Enemy,都分别继承了接口IDamageable,继承后,两个类都需要去实现接口中的所有成员即属性Health和方法Damage,如下所示。

public class Player : MonoBehaviour, IDamagable
{
    public int Health { get; set; }

    public void Damage(int damageAmount)
    {
        Health -= damageAmount;
        transform.GetComponent<MeshRenderer>().material.color = Color.red;
    }
}
public class Enemy : MonoBehaviour, IDamagable
{
    public int Health { get; set; }

    public void Damage(int damageAmount)
    {
        Health -= damageAmount;
        transform.GetComponent<MeshRenderer>().material.color = Color.red;
    }
}

有人可能又要问了:Damage方法中参数damageAmount是整型,可以是别的其它数据类型么,这样方法的扩展性更强。当然可以,那就要调整一下接口的声明,要使用到泛型。

public interface IDamagable<T>
{
    int Health { get; set; }

    void Damage(T damageAmount);
}

就简单的加了个来代表数据类型,是不是很方便。在对应的继承中也要相应加上,以Player脚本中为例,如果需要int型则在继承中将T对应改为int即可。

public class Player : MonoBehaviour, IDamagable<int>
{
    public int Health { get; set; }

    public void Damage(int damageAmount)
    {
        Health -= damageAmount;
        transform.GetComponent<MeshRenderer>().material.color = Color.red;
    }
}

*五. 游戏编程用途

这一块也是看到学到的…
创建了一个Main脚本,主要用途就是当通过射线检测来对之前Player和Enemy物体进行伤害判断。代码如下。

public class Main : MonoBehaviour
{
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;
            
            if(Physics.Raycast(ray, out hitInfo))
            {
                
                if (hitInfo.transform.name == "Enemy")
                    hitInfo.transform.GetComponent<Enemy>().Damage(500);
                else if(hitInfo.transform.name == "Player")
                    hitInfo.transform.GetComponent<Player>().Damage(500);

                //问:那如果要判断几十 几百个对象都用分支去判断么?
                
            }
        }
    }
}

可以看到我们在使用射线检测到对应物体时,需要根据相应的物体名来进行伤害的逻辑处理,那如果有几百个物体对象,那岂不是代码量上天了,这里就可以用到接口了。因为接口是这两个物体对象均含有的部分,可以直接通过接口来进行逻辑处理。

public class Main : MonoBehaviour
{
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;
            
            if(Physics.Raycast(ray, out hitInfo))
            {
                IDamagable<int> obj = hitInfo.transform.GetComponent<IDamagable<int>>();

                if (obj != null)
                    obj.Damage(500);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值