这是多态的例子吗?

时间:2011-04-04 19:44:57

标签: c# polymorphism

我知道什么是多态,但却无法清楚地理解它。我的代码也是如下:

class Human
{
   public virtual void CleanTheRoom()
   {
   }
}
class Woman:Human
{
   public override void CleanTheRoom()
   {
     //women clean faster
   }
}
class Man:Human
{
   public override void CleanTheRoom()
   {
     //men clean slower, different code here
   }
}
class Child:Human
{
   public override void CleanTheRoom()
   {
     //empty ... children are lazy :)
   }
}

我是否应该解释这是多态的,因为基类Human中的所有派生类都包含方法CleanTheRoom但是它们中的每一个都以不同的方式实现?

8 个答案:

答案 0 :(得分:21)

当您想要在某种类型的CleanTheRoom()上调用Human方法时,多态性的好处就出现了,但您并不关心哪一种具体。

通过在基类级别CleanTheRoom()定义Human,只要您使用Human的实例,就可以在应用程序的其他位置编写更简洁,更清晰的代码,无论是是ManWomanChild

例如,

多态性允许您避免丑陋的条件语句,其中您明确检查每种类型的Human并调用不同的方法:

不可

private void SomeMethod(Human h)
{
    //some logic
    h.CleanTheRoom();
    //more logic
}

<强>为:

private void SomeMethod(Human h)
{
    //some logic
    if (h is Man)
        CleanRoomSlowly();
    else if (h is Woman)
        CleanRoomQuickly();
    else if (h is Child)
        GoofOff();
    //some logic
}

答案 1 :(得分:16)

你所拥有的是继承的一个很好的例子。多态性特指能够通过使用单一类型(父类或接口)来引用不同类型的对象,这种类型的继承使得这种对象成为可能。像这样:

List<Human> humans = new ArrayList<Human>();

humans.add(new Woman());
humans.add(new Woman());
humans.add(new Man());
humans.add(new Child());
humans.add(new Child());

foreach(Human hum in humans) {
   hum.CleanTheRoom(); //I don't know the type of hum, but I don't care
}

说我一直在从不同的地方收集人类的实例 - 我不知道每个人的类型。但我仍然可以迭代它们并调用CleanTheRoom(),因为它们共享一个父类。

我将添加一个真实世界的例子。假设我有一个Invoice类,其中包含针对不同类型发票的各种子类 - 对于服务客户和可能一次性购买的客户,可能有不同类型的Invoice。有时候我非常关心这些差异,而我只处理一种类型。但有时我想循环查看本月的所有发票并打印出来。如果父类具有print()方法(可能由不同类型实现不同),那么我可以这样做。

答案 2 :(得分:0)

是的,这是正确的。你可以调用方法CleanTheRoom(),而不知道它是什么样的人类。

Here你有一些基本的例子。

答案 3 :(得分:0)

我认为你没有看到好处,这是你完全理解多态性所缺少的关键。我会试着举个例子:

假设您有一个简单的CRUD表单。这是保存按钮的代码:

var Client = PopulateDTO(); //put all the values in the controls, to an object

if(Action==Actions.Create){
  _repository.Create(Client);
}
else if(Action==Actions.Update){
  _repository.Update(Client);
}
else if(Action==Actions.Delete){
  _repository.Delete(Client);
}

this.Close();

此代码有效,但代码错误,难以阅读。让我们使用多态(和策略模式):

public abstract class BaseStrategy{
  abstract void Do(ClientDto Client);
}

public class CreateStrategy:BaseStrategy{
  public override void Do(ClientDto Client){
    _repo.Save(Client);
  }
}

public class UpdateStrategy:BaseStrategy{
  public override void Do(ClientDto Client){
    _repo.Update(Client);
  }
}

public class DeleteStrategy:BaseStrategy{
  public override void Do(ClientDto Client){
    _repo.Delete(Client);
  }
}

因此,我们有一个抽象类和3个实现,每个实现与客户端对象做一些事情。现在,表单中保存按钮的代码将是:

BaseStrategy stg = GetCorrectStrategy();

var Client = PopulateDTO();

stg.Do(Client);

this.close;

GetCorrectStrategy()方法将实例化正确的策略实现,具体取决于用户是否正在创建,编辑或删除客户端。

我希望这个答案会对你有所帮助。但如果没有帮助你,我建议你阅读一下策略模式,在我看来,这是多态性的最佳用途之一

答案 4 :(得分:0)

由于有几个人已经提供了很好的多态性示例,我将提供一个不同的视角,真正帮助我理解它。

在函数式编程中,函数是第一类概念,与OOP相反,对象是最重要的。

多态性是指OOP与FP的模式匹配。这是一个使用模式匹配的函数(使用ML样式语法)。

 let f x =
        match x with
        | T -> //do stuff with a T to return some value
        | S -> //do stuff with an S to return some value
        | U -> //do stuff with a U to return some value
        | V -> //do stuff with a V to return some value

因此,当您使用函数f时,可以向其传递T,S,U或V类型的对象。在强类型FP语言(如F#)中,x的类型表示为T|S|U|V。这些类型通常称为Sum类型或Tagged Unions。

如果我们修改你的例子以使Human成为一个抽象类,那么很明显OOP中的多态性只是为你提供了一种表达和类型的方法。

因此,CleanTheRoom是一个采用Human类型的函数。但Human只是类型Man|Woman|Child的名称,它是和类型。像C#这样的语言和像F#这样的函数语言之间的巨大差异在于,一个人将对象视为顶级事物,而另一个人将函数视为顶级事物。而且,像C#这样的OOP语言中的所有内容都必须具有名称。在函数式语言中,我们可以表示类型Man|Woman|Child,而无需明确命名它。

关键是不要将代码视为具有不同的CleanTheRoom方法,而是将CleanTheRoom视为采用类型Man|Woman|Child的一种方法(名为{{1} }})。多态性只是实现细节。

总之,多态(特别是抽象类)基本上只是为您提供了一种命名和类型并进行模式匹配的方法。

请参阅:

答案 5 :(得分:0)

C#中的一个例子:

这是我的班级文件

class parent
    {
        public virtual string saySomething(string s)
        {
            return s+":Parent";
        }
    }
    class man : parent
    {
        public override string saySomething(string s)
        {
            return s+":Man";
        }
    }
    class woman : parent
    {
        public override string saySomething(string s)
        {
            return s+":Woman";
        }
    }
    class child : parent
    {
        public override string saySomething(string s)
        {
            return s+":Child";
        }
    }

创建四个按钮和一个标签。

这是一个简单的form1上的实现

private void Form1_Load(object sender, EventArgs e)
        {
             p1= new parent();       

        }

        private void button1_Click(object sender, EventArgs e)
        {            
            label1.Text = p1.saySomething("I am parent!");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            p1 = new man();
            label1.Text = p1.saySomething("I am man!");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            p1 = new woman();
            label1.Text = p1.saySomething("I am woman!");
        }

        private void button4_Click(object sender, EventArgs e)
        {
            p1 = new child();
            label1.Text = p1.saySomething("I am child!");
        }

是运行时多态吗? P1是一个对象。根据情况(上下文),单击按钮,它正在执行不同的代码段。因此,p1的行为会有所不同,具体取决于点击事件。

答案 6 :(得分:0)

class Program
{
    static void Main(string[] args)
    {
        List<ICleanTheRoom> cleanerList = new List<ICleanTheRoom>
            {
                new Child(), 
                new Woman(), 
                new Man()
            };
        foreach (var cleaner in cleanerList)
        {
            cleaner.CleanTheRoom();
        }
    }
}

internal interface ICleanTheRoom
{
    void CleanTheRoom();
}

// No need for super type

//class Human : ICleanTheRoom
//{
//   public virtual void CleanTheRoom()
//   {
//   }
//}


internal class Woman : ICleanTheRoom
{
    public void CleanTheRoom()
    {
        throw new NotImplementedException();
    }
}

class Man: ICleanTheRoom
{
    public void CleanTheRoom()
    {
        throw new NotImplementedException();
    }
}

class Child: ICleanTheRoom
{
    public void CleanTheRoom()
    {
        throw new NotImplementedException();
    }
}

答案 7 :(得分:0)

它是每次在运行时创建的新对象,显然继承但没有多态。