我有两个对象, Bird 和 Dog 。 Bird 和 Dog 对于大约50%的方法/属性具有相同的实现,但对于其他50%的方法和属性具有不同的无关方法和属性。
我正在重构,我不知道什么是最好的策略。
我尝试定义一个超类 Animal 来实现超类中的常用方法,并让子类定义自己的方法/属性。
我写了一个工厂,它返回了一个或另一个 - 这一切似乎都是正确的......但是在编写调用代码时我很困惑......例如。
public class Animal{
public string Talk(){ return "yak yak yak";
}
public class Dog:Animal{
public string Walk(){ return "walk walk walk"; }
}
public class Bird:Animal{
public string Fly(){ return "flap flap flap"; }
}
...
Animal thing = CreatureFactory.GetCreature(modifier);
当我想使用事物来谈话时,没有问题,
Debug.Print(thing.Talk());
但是当我作为程序员知道我想要飞时,我会把它投到 Bird 吗?这似乎是错误的......但在 Dog 上定义 Fly 方法似乎也是错误的。
答案 0 :(得分:3)
你要么把它变成一只鸟:
Debug.Print(((Bird)thing).Fly());
或者你一直把它当作一只鸟:
// depending on how the factory works, might not need the cast
Bird thing = (Bird) CreatureFactory.GetCreature(modifier);
Debug.Print(bird.Fly());
答案 1 :(得分:2)
我接近它的方法是让工厂方法返回一个具体类型而不是超类。您仍然可以将它传递给可以在超类上运行的方法,但是您可以在需要时使用具体类的项目,而不需要将其强制转换。
Bird bird = CreatureFactory.GetBird();
或
Dog dog = CreatureFactory.GetDog();
现在,您仍然可以将它们用作Animal
。
public class Trainer
{
public void TeachToSpeak( Animal animal )
{
...
animal.Talk();
}
}
但是因为它们被输入到具体类中,所以你可以使用它们不适当分享的方法。
答案 2 :(得分:2)
根据您的示例,当您希望Animal
飞行时,执行飞行的班级正在使用错误的班级 - 它应该使用Bird
本身或某些ICanFly
接口
虽然其他答案说你可以通过强制转换来实现,但代码的可读性会受到影响。当您有工厂创建对象时,绝对没有理由将这些对象转换为其他类型。当你开始转换为其他类型时,你的类违反了单一责任原则,这也是一个坚实的论点。
答案 3 :(得分:1)
我会说: 如果你的狗也有一种方法可以提出“运动”的想法,我会改变飞行的名字,然后步行到“移动”,然后调用它。 如果你的狗没有这样的东西,开发者不应该在任何物体上召唤它,因为并非所有动物都可以飞行:)
答案 4 :(得分:1)
首先,我会在名为Move()
的基类上放置一个虚方法,并在派生类中覆盖它。
(以下是C#)
public abstract class Animal {
public string Talk() { return "yak yak yak"; }
public virtual string Move();
}
public class Dog : Animal {
public override string Move() { return "walk walk walk"; }
}
public class Bird : Animal {
public override string Move() { return "flap flap flap"; }
}
但是要回答你的问题,如果你希望动物移动(如果它只能)它可以飞行,你可以定义一个IFlyingAnimal
接口并用Bird
实现它。然后,您可以测试Animal
是否实现了该接口。如果是,请将其投放到IFlyingAnimal
并调用其Fly()
方法。
public interface IFlyingAnimal {
string Fly();
}
public class Bird : Animal, IFlyingAnimal {
public string Fly(){ return "flap flap flap"; }
}
//later, in your main program
public string FlyIfYouCan(Animal animal) {
if (animal is IFlyingAnimal)
return ((IFlyingAnimal)animal).Fly();
return "I can't fly!";
}
你没有拥有来使用接口;你可以改用if (animal is Bird)
。但这样做更好的做法;鸟类不是唯一可以飞行的动物,因此您根据项目做什么做出决定,而不是 。这就是界面的用途。