【发布时间】:2021-09-17 01:26:35
【问题描述】:
我主要来自函数式语言背景,我不知道如何在面向对象语言中做好这种模式。
假设我有一些 Animal 类和子类以及一个 AnimalManager。我想要一个 AnimalManager 上的“add”方法,它具有不同的行为,具体取决于我添加的是猫还是狗。像这样的东西(没有特定的语言):
class Animal
class Cat : Animal
class Dog : Animal
class AnimalManager {
void add(Animal a) {
a match {
case Cat => // do something with cats
case Dog => // do different something with dogs
}
}
}
现在,如果我使用像 C++ 这样不支持以这种方式匹配类型的语言怎么办。我能想到的两个解决方案是:
- 使用 dynamic_cast。 但是,有人告诉我应该避免动态转换,因为它会导致运行时错误,所以这可能是不好的做法。
- 使用虚函数。我可以做类似以下的事情(同样没有特定的语言,但你应该明白要点):
class Animal {
virtual void beAdded(AnimalManager am)
}
class Cat : Animal {
void beAdded(AnimalManager am) {
am.doThingsWithCats(this)
}
}
class Dog : Animal {
void beAdded(AnimalManager am) {
am.doThingsWithDogs(this)
}
}
class AnimalManager {
void doThingsWithDogs(Dog d) {
// do something with dogs
}
void doThingWithCats(Cat d) {
// do something with cats
}
void add(Animal a) {
a.beAdded(this)
}
}
这显然是非常尴尬的,还有其他问题(现在 Animal 需要了解 AnimalManager?)。
在面向对象语言中实现这种模式的最佳方法是什么?这里有一些我应该知道的“设计模式”吗?
【问题讨论】:
-
从 OO 的角度来看,尴尬的是在添加猫和狗时对它们做一些不同的事情,而不是在添加它们后为您想要对它们做的事情使用虚拟函数。
-
有点切线但是...what is
AnimalManager?而且您编写尝试的解决方案的方式似乎在某种程度上重塑了访问者(一种常见的设计模式)。 -
你没有。您使用虚拟方法,根据需要在每个子类型中执行不同的操作。任何时候您需要知道实际的子类型,您都可能做错了。
-
@KidKush420:如果
AnimalManager需要知道它管理的是哪种动物,那么Animal在其作为基类的工作中失败,或者@ 987654327@ 管理Animals 的工作失败了。任何需要Animal的东西都不应该关心它是哪一种,如果是这样,你做错了什么或者你不应该使用 OOP。 -
@KidKush420: "它只是对动物做一些非特定的事情" 但它对
Animals 做了一些非常特定的事情.如此具体以至于它需要知道它是什么类型的Animal才能完成它的工作。问题是它为什么需要这个。
标签: c++ oop design-patterns types