重构两个包含一半相关函数和一半不相关函数的类时应使用哪种设计模式?
我有两个对象,鸟和狗。 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);
当我想使用 thing 来 Talk< /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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
你要么把它扔给一只鸟:
要么你一直把它当作一只鸟:
You either cast it to a bird:
or you treat it as a bird the whole time:
给定您的示例,当您希望您的
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 theBird
itself or someICanFly
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.
我处理它的方法是让工厂方法返回具体类型而不是超类。您仍然可以将其传递给可以对超类进行操作的方法,但是您可以在需要时使用具体类的一项,并且不需要强制转换它。
或者
现在,您仍然可以将它们用作
动物
。但由于它们是针对具体类的类型,因此您可以适当地利用它们不共享的方法。
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.
or
Now, you can still use them as an
Animal
.But since they are typed to the concrete class, you can make use of the methods they don't share as appropriate.
我想说:
如果你的狗也有一个给出“运动”概念的方法,我会将“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 :)
一方面,我会在基类上放置一个名为
Move()
的虚拟方法,并在派生类中重写它。(以下是 C#)
但是为了回答你的问题,如果你希望动物在(且仅当)它可以飞时移动,你可以定义一个
IFlyingAnimal
接口并使用Bird
来实现它。然后您可以测试Animal
是否实现该接口。如果是,则将其转换为IFlyingAnimal
并调用其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#)
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 withBird
. Then you can test whether anAnimal
implements that interface. If it does, cast it toIFlyingAnimal
and call itsFly()
method.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.