使用多态性,可以动态地定义调用的方法, 而不是在编译期间定义。 编译器创建一个虚拟方法表 (vtable),其中列出了可以在运行期间调用的方法, 它根据运行期间的类型调用方法。
public static void DrawShape(Shape shape)
{
shape.Draw();
}
上例中, DrawShape 方法有一个 shape对象做为参数, 注意,任何Shape类和派生自 Shape的类都可以传递进来。
对于多态性这个概念,我个人总结了一句话: 如果有同样一个或一组行为的对象,他们应该有所关联(可以继承同一个接口,或父类) ,这样就可以动态的管理它们。
假设我们开发了一个简易的打怪小游戏, 那么就有了 主角和小怪, 主角有一个, 小怪有很多个,
我们就分析一下小怪的行为吧 -> 小怪的行为: 行走、 攻击 、受伤 、死亡
下面写代码:
// 这是抽象出来的父类
public class Monster
{
#region 属性
public string Name { get; } // 名称
public int HP { get; } // 血量
public int ATK { get; } // 攻击力
#endregion
#region 构造函数
public Monster (string name, int hp, int atk)
{
Name = name;
HP = hp;
ATk = atk;
}
#endregion
#region 函数
// 受伤
public virtual void Harm(int value) {}
// 行走
public virtual void Walk() {}
// 攻击
public virtual void Attack() {}
// 死亡
protected virtual void Die() {}
#endregion
}
// 这是具体的小怪类 (小鬼)
public class Kobold : Monster
{
#region 构造函数
public Kobold (string name, int hp, int atk):base(name, hp, atk) {}
#endregion
#region 函数
// 受伤
public override void Harm(int value)
{
// 1.受到攻击时血量就要相应的减少
HP -= value;
// 2.当自身的血量 <= 0 时 触发 Die
if(HP <= 0) Die();
}
// 行走
public override void Walk()
{
// 播放行走动画
// animation.Walk();
}
// 攻击
public override void Attack()
{
// 1.播放攻击动画
// animation.Attack();
// 2.检测是否攻击到目标 (这里假设攻击到了)
target.Harm(ATK);
}
// 死亡
protected override void Die()
{
// 1.播放死亡动画
// animation.Die();
// 2.游戏结束
// todo
}
#endregion
}
public void Main()
{
// 我们在场景中创建了一个怪
Kobold monster = new Kobold("吸血妖", 100, 5);
// 让怪兽走起来
monster.Walk();
// 模拟主角攻击了怪兽,给它 20点伤害
AttackMonster(monster, 20);
// 我们在场景中再创建了一个怪
Kobold monster2 = new Kobold("巡逻妖", 500, 15);
// 让怪兽走起来
monster2 .Walk();
// 模拟主角攻击了怪兽,给它 50点伤害
AttackMonster(monster2 , 50);
}
public static void AttackMonster( Monster monster , int atk)
{
monster.Harm(atk);
}
好了,代码就写这么多吧。 其实讲多态性不应该写代码的, 这个东西代码很难来表达出它的真正含义。
但是我还是写了代码,为什么呢? 因为我要告诉大家的是只要记住一点, 那就是不管谁继承了 Monster 类, 它下面的几个行为就会存在,不管重写不重写它,它都是存在的。不管你有几千个几万个甚至更多的小怪, 只要主角砍到其中一个就可以控制它,让它受伤害,而没有被砍到的小怪该干嘛干嘛!