9

标题可能不清楚,但请看下面的图案

public abstract class Animal
{

    public abstract Dog GetDog { get; }

    public abstract Cat GetCat { get; }

}

public class Dog : Animal
{

    public override Dog GetDog {
        get { return this; }
    }

    public override Cat GetCat {
        get { return null; }
    }

}

在基类中具有属性并返回派生类型是否被认为是一种不好的做法。或者我应该做类似的事情

public abstract AnimalTypeEnum AnimalType { get; }

编辑:根据评论,我想我应该更清楚我想要实现的目标。Dogor类的新实例Cat将由基于特定条件的单独函数创建,然后将Animal类型返回给调用者。调用方法将检查返回实例的类型并相应地使用它。

public Animal CreateAnimal(string path)
{

    //Process the document in path and create either a new instance of dog or cat

    Dog dg = new Dog();

    return dg;

}
4

5 回答 5

19

如果你只想要你所衍生的动物,你可以这样做:

public abstract class Animal<T> where T: Animal<T>
{
    public T GetAnimal 
    {
        get { return (T)this; }
    }
}

public class Dog : Animal<Dog>
{
}

public class Cat : Animal<Cat>
{
}

public class Giraffe : Animal<Giraffe>
{
}

你这样称呼:

var cat = new Cat();
var dog = new Dog();
var giraffe = new Giraffe();
Cat cat2 = cat.GetAnimal;
Dog dog2 = dog.GetAnimal;
Giraffe giraffe2 = giraffe.GetAnimal;
于 2013-08-13T20:58:14.790 回答
7

调用方法将检查返回实例的类型并相应地使用它。

有你的问题。需要这样做是代码气味。你应该能够把它当作一个物体来对待,而不是区别对待狗和猫。

如果您需要显示任一动物的内容,则覆盖ToString两个类的方法并调用ToString动物。如果您需要知道狗或猫的名称,请添加一个Name属性到Animal. 如果可能的话,您应该在此处使用多态性,以便使用该对象的任何内容都将其视为一个Animal并且简单地涉及由于同一方法的不同实现而发生的不同事情。

如果你真的,真的需要知道Animal是 aDog还是 aCat那么你可以使用isoras运算符;您不需要添加您在 OP 中显示的所有代码。

于 2012-10-18T19:10:15.123 回答
5

不,你做错了。

更好的办法是有一个单一的方法。

public abstract Animal getAnimal();

任何派生类都将知道如何返回自己。我希望这是有道理的。但是我认为您也不想返回 Animal 。没有意义。

Animal dog = new Dog() ;
dog.getAnimal(); 

令人困惑的权利?

你可以有一个动物/列表数组,遍历集合并检查如下:

if(animal is Dog)

但是您仍在检查类型。如果您想使用基类,请使用它以使其有意义并公开通用方法。

于 2012-10-18T18:45:20.317 回答
1

这是一个非常基础的设计,因为它违反了开闭原则。您希望您的课程对扩展开放但对修改关闭。如果明天你想添加另一个类会发生什么?

public class Donkey : Animal
{
}

您将不得不去更改基类,使其具有属性GetDonkey。您还必须去更改所有使用您的班级的班级并添加if (animal.GetDonkey == null)

你应该做的是使用这样的工厂设计模式:

public static class AnimalFactory
{
  public static Dog GetDog()
  {
    return new Dog();
  }

  public static Cat GetCat()
  {
    return new Cat();
  }
}

或者您应该使用@Lews Therin建议的虚拟方法。

于 2012-10-18T18:57:29.493 回答
-2

拥有只返回它们被调用的对象的属性似乎不是很有用。

也许您只是在寻找一种从超类到子类的方法?如果是这样,只需使用演员表:

Animal a = new Cat();

try
{
    Dog d = (Dog)a;
}
catch (InvalidCastException)
{
    try
    {
        Cat c = (Cat)a;
    }
    catch (InvalidCastException)
    {
    }
}
于 2012-10-18T18:54:02.967 回答