在重构包含一半相关函数和一半不相关函数的两个类时要使用哪种设计模式?

时间:2011-02-07 22:28:42

标签: oop design-patterns

我有两个对象, 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 方法似乎也是错误的。

5 个答案:

答案 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)。但这样做更好的做法;鸟类不是唯一可以飞行的动物,因此您根据项目做什么做出决定,而不是 。这就是界面的用途。