多态(继承多态和接口多态、多态数组)

使用基类变量引用子类对象,或使用接口变量引用实现了此接口的对象。这其实就是多态编程。

多态编程的基本原理是:使用基类或接口变量编程。
在多态编程中,基类一般都是抽象基类,其中拥有一个或多个抽象方法,各个子类可以根据需要重写这些方法。或者使用接口,每个接口都规定了一个或多个抽象方法,实现接口的类根据需要实现这些方法。
因此,多态的实现分为两大基本类别:继承多态和接口多态。

在编程中应用多态,可以将其简化为以下两句:
  应用继承实现对象的统一管理。
  应用接口定义对象的行为特性。

一、继承多态

假设某动物园管理员(Class Feeder)每天需要给他所负责饲养的狮子(Class Lion)、猴子(Class Monkey)和鸽子(Class Pigeon)喂食,三种动物吃的东西不一样。


饲养员小李喂食的过程如下:

static void Main(string[] args)
{
  Monkey m = new Monkey();
  Pigeon p = new Pigeon();
  Lion l = new Lion();
  Feeder f = new Feeder();
  f.Name = "小李";
  f.FeedMonkey(); //喂猴子
  f.FeedPigeon(); //喂鸽子
  f.FeedLion(); //喂狮子
}

如果动物园领导看小李工作努力,又把大熊猫交给他管理。这时,我们的程序不得不给Feeder 类增加第四个方法:FeedPanda()。
万一小李后来又不管理鸽子了,那不又得从Feeder 类中删除FeedPigeon()方法吗?
这种编程方式很明显是不合理的。
可以应用多态的方法解决。
很明显,狮子、猴子和鸽子都是一种动物,因此,可以建立一个Animal 抽象基类,让狮子、猴子和鸽子从其派生出来。由于不同的动物吃不同的食物,所以在Animal 类中定义一个抽象的eat()方法,由子类负责实现此方法。

abstract class Animal
{
public abstract void eat();
}
//狮子
class Lion:Animal
{
public override void eat()
{
//吃肉
}
}
//猴子
class Monkey:Animal
{
public override void eat()
{
//吃香蕉
}
}
//鸽子
class Pigeon:Animal
{
public override void eat()
{
//吃大米
}
}

现在,可以将Feeder 类的三个喂养方法合并为一个FeedAnimal。


Feeder 类代码如下:
//动物园饲养员
class Feeder
{
public String Name;
public void FeedAnimal(Animal animals)//在函数参数列表里声明一个对象变量参数animals
{
animals.eat();
}
}

现在,喂养过程变为:
static void Main(string[] args)
{
Monkey m = new Monkey();
Pigeon p = new Pigeon();
Lion l = new Lion();
Feeder f = new Feeder();
f.Name = "小李";
f.FeedAnimal(m);//喂猴子
f.FeedAnimal(p);//喂鸽子
f.FeedAnimal(l);//喂狮子
}

上述代码中有连续三句的动物喂养语句,还可以进一步使用多态的方法消除之。
修改Feeder 类的定义,给其增加一个新方法:FeedAnimals(),新方法完成的功能是喂养一群动物,它接收一个类型为Animal 的数组:
//动物园饲养员
class Feeder
{
  public String Name;
  //喂养一群动物
  public void FeedAnimals(Animal[] ans)//在函数参数列表里声明一个对象变量ans,该变量是一个数组参数

 {                                                            //数组ans 的元素类型为Animal,因此,可以在其中存入任何一个Animal 的子类。具有这种特性的数组称为“多态数组”。
    foreach (Animal an in ans)//在函数参数列表里声明一个对象参数an,每次循环的an并不是同一个an
    {
      an.eat();
    }
  }
}
喂养过程现在的代码如下:

static void Main(string[] args)
{
//动物数组
Animal[] ans={new Monkey(),new Pigeon(),new Lion()};//不管有几种动物,只要将所有这些动物都“塞”进多态数组中,Feeder 类的FeedAnimals 方法不用改就可以使用。
Feeder f = new Feeder();
f.Name = "小李";
f.FeedAnimals(ans);
}

二、接口多态

Word 中可以方便地绘制各种图形,而且可以对图形做各种操作,比如移动、缩放、旋转、填充等。

下面我们从面向对象的角度,思索一下如何克隆Word 的绘图功能为一个小型的绘图软件。

首先,这个软件应该拥有绘制多种图形的功能。因此,可以建立一个图形对象继承体系。


每一个Word绘图页上的图形都可以看成是Shape 对象的集合。将这些对象放入到一个多态对象集合中,就保存了当前页面上的图形。将这一多态集合保存到磁盘文件,就相当于保存了用户的绘图结果。当打开磁盘文件时,在内存中重建多态对象集合,依次访问集合中的每一个对象,通知它们“自己绘制自己”,就重现了用户上次保存时的绘图结果。从这点出发,就知道应该给Shape 基类增加一个抽象方法:DrawMyself(),让每个图形子类去负责实现具体的绘图方法。

象C#和Java 这类的面向对象语言,一个类只能有一个父类,而且,不同的图形对象可以拥有不同的操作,比如对于矩形对象,可以同时改变其长和宽,但对直线对象而言,只有改变长度是允许的操作,因此,不太适合使用继承来实现操作图形对象的功能。比较好的方案是将常见操作抽象为接口。哪种图形对象可以进行哪种操作,就让它实现这个接口。


因此,就有可能编写这样一个方法,移动任何一个“可移动的”图形对象:
public void MoveShape(IMove obj)
{
Obj.Move();
}

类似地,可以编写这样一个方法,同时移动多个“可移动的”对象:
public void MoveShapes(IMove[] objs)
{
Foreach(Shape s in objs)
{
s.Move();

}
}

上述代码都是针对接口变量进行编程的,不涉及任何具体的图形类,因而,可以移动任何一个或一组实现了特定接口的图形对象。



  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值