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

发布于 2024-10-16 05:16:04 字数 918 浏览 4 评论 0原文

我有两个对象,BirdDog 大约 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);

当我想使用 thingTalk< /strong> 没有问题,

Debug.Print(thing.Talk());

但是作为程序员,当我知道我希望它时,我是否可以将其投射到呢?这似乎是错误的......但在 Dog 上定义 Fly 方法似乎也是错误的。

I have two objects, Bird and Dog. Bird and Dog have identical implementations for about 50% of methods/properties but different unrelated methods and properties for the other 50%.

I'm refactoring and I don't know what is the best strategy.

I tried defining a superclass Animal to implement common methods in the superclass and let the children classes define their own methods/properties.

I wrote a factory that returned one or the other - this all seems right... but I'm confused when writing the calling code.. e.g.

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

When I want to use thing to Talk there's no problem,

Debug.Print(thing.Talk());

but what about when as the programmer I know I want it to Fly do I cast it to Bird? That seems wrong... but defining a Fly method on Dog seems wrong too.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

拿命拼未来 2024-10-23 05:16:04

你要么把它扔给一只鸟:

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());

You either cast it to a bird:

Debug.Print(((Bird)thing).Fly());

or you treat it as a bird the whole time:

// depending on how the factory works, might not need the cast
Bird thing = (Bird) CreatureFactory.GetCreature(modifier);
Debug.Print(bird.Fly());
扮仙女 2024-10-23 05:16:04

给定您的示例,当您希望您的 Animal 飞行时,执行飞行的类正在使用错误的类 - 它应该使用 Bird 本身或某些 ICanFly 界面。

虽然其他答案说您可以通过强制转换来实现,但代码的可读性会因此受到影响。当您使用工厂创建对象时,绝对没有理由将这些对象转换为另一种类型。还有一个有力的论据表明,当您开始转换为其他类型时,您的类违反了单一职责原则。

Given your example, when you want your Animal to fly, the class doing the flying is working with the wrong class -- it should be using the Bird itself or some ICanFly interface.

While the other answers said you can do it with casting, the readability of your code will suffer because of it. When you have factories creating your objects, there's absolutely no reason you should be casting those objects to another type. There's also a solid argument that your classes are violating the Single Responsibility Principle when you start casting to other types.

<逆流佳人身旁 2024-10-23 05:16:04

我处理它的方法是让工厂方法返回具体类型而不是超类。您仍然可以将其传递给可以对超类进行操作的方法,但是您可以在需要时使用具体类的一项,并且不需要强制转换它。

Bird bird = CreatureFactory.GetBird();

或者

Dog dog = CreatureFactory.GetDog();

现在,您仍然可以将它们用作动物

public class Trainer
{
     public void TeachToSpeak( Animal animal )
     {
          ...
          animal.Talk();
     }
}

但由于它们是针对具体类的类型,因此您可以适当地利用它们不共享的方法。

The way I would approach it is to have the factory method return a concrete type rather than the superclass. You can still pass it to methods that can operate on the superclass, but you have an item of the concrete class to work with when needed and don't need to cast it.

Bird bird = CreatureFactory.GetBird();

or

Dog dog = CreatureFactory.GetDog();

Now, you can still use them as an Animal.

public class Trainer
{
     public void TeachToSpeak( Animal animal )
     {
          ...
          animal.Talk();
     }
}

But since they are typed to the concrete class, you can make use of the methods they don't share as appropriate.

忘你却要生生世世 2024-10-23 05:16:04

我想说:
如果你的狗也有一个给出“运动”概念的方法,我会将“fly and walk”的名称更改为“move”,然后调用它。
如果你的狗没有这样的东西,开发者不应该能够在任何物体上调用它,因为并不是所有的动物都能飞:)

I would say:
if your dog has also a methods that gives the idea of "movement", I would change the name of fly and walk to "move" and then call it.
If your dog doesn't have anything like that, the dev shouldn't be able to call it on an anymal object, because not all animals can fly :)

我三岁 2024-10-23 05:16:04

一方面,我会在基类上放置一个名为 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) 来代替。但这样做是更好的做法;鸟类并不是唯一会飞的动物,因此您要根据您的物品用途来做出决定,而不是它是什么。这就是接口的用途。

For one thing, I would put a virtual method on the base class called Move() and override it in the derived classes.

(The following is 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"; }
}

But to answer your question, if you want the animal to move if (and only if) it can fly, you could define an IFlyingAnimal interface and implement it with Bird. Then you can test whether an Animal implements that interface. If it does, cast it to IFlyingAnimal and call its Fly() method.

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

You don't have to use an interface; you could just use if (animal is Bird) instead. But it's much better practice to do it this way; birds aren't the only animals that can fly, so you're making the decision based on what your item does, not what it is. That's what interfaces are for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文