从基类返回派生的类实例



标题可能不清楚,但请查看下面的模式

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; }

编辑:根据评论,我想我应该更清楚自己要实现的目标。DogCat类的新实例将由一个基于某些标准单独的函数创建,然后将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;
}

如果您只想从您派生的动物,可以做到这一点:

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;

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

有您的问题。需要这样做的代码气味。您应该能够将其视为一个物体,而不是对狗和猫的对待。

对待狗和猫。

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

如果您真的需要知道AnimalDog还是Cat,则可以使用isas操作员;您不需要添加Op。

中显示的所有代码

不,你做错了。

更好的是拥有一种方法。

public abstract Animal getAnimal();

任何派生的类都会知道如何返回。我希望这是有道理的。但是,我认为您也不想归还动物。没有意义。

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

混淆吧?

您可能有一系列动物/清单,通过收藏品迭代并像这样检查:

if(animal is Dog)

,但您仍在检查类型。如果您想使用基类具有它,以便它有意义并公开了常见的方法。

这是一个真正的基本设计,因为它违反了开放式原理。您希望您的课程开放以进行扩展,但要进行修改。如果明天您想添加另一堂课会发生什么?

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建议的虚拟方法。

拥有只能返回对象的属性似乎不是很有用。

也许您只是在寻找一种从超级阶级到子类降低的方式?如果是这样,请使用铸件:

Animal a = new Cat();
try
{
    Dog d = (Dog)a;
}
catch (InvalidCastException)
{
    try
    {
        Cat c = (Cat)a;
    }
    catch (InvalidCastException)
    {
    }
}

最新更新