在OO设计中避免RTTI
我最近在一些论坛上看到一个OO设计问题,并开始考虑使用RTTI。然而,这一定是糟糕的设计,但我无法想到替代方案。这是一个简单的问题:
使用 OO 概念为以下场景创建一个 C++ 程序 -
我的狗名叫巴迪,住在后院。晚上,当他看到猫或松鼠来拜访时,他就会吠叫。如果他看到一只青蛙并且他饿了,他就会吃掉它。如果他看到一只青蛙并且他不饿,他就会和它玩。如果他已经吃了两只青蛙,但仍然很饿,他就会放手。如果他看到郊狼,他就会大声呼救。有时他的朋友斯波特过来,他们互相追逐。如果他看到任何其他动物,他只是看着它。我希望你有一个动物类,以及一个从动物类继承的猫、狗、松鼠、郊狼类。
我开始考虑在狗类中使用 see() 方法,该方法采用 Animal 参数,然后检查对象的实际类型(青蛙、猫等)并根据实际类型采取所需的操作 - 玩耍、追逐等。然而这需要RTTI,这一定是糟糕的设计。有人可以建议一个更好的设计来避免 RTTI 并指出我的想法中的错误吗?
I recently saw an OO design question on some forum and started thinking of using RTTI. However this must be bad design but I am unable to think of an alternative. Here is the simple question :
Create a C++ program for the following scenario using OO concepts -
My dog, named Buddy, lives in the backyard. He barks at night when he sees a cat or a squirrel that has come to visit. If he sees a frog, and he is hungry, he eats it. If he sees a frog and he isn't hungry, he plays with it. If he has eaten 2 frogs already, and is still hungry, he will let it go. If he sees a coyote, he crys for help. Sometime his friend Spot stops by, and they chase each other. If he sees any other animal, he simply watches it. I would expect that you would have an animal class, and a cat, dog, squirrel, coyote class that inherits from the animal class.
I started thinking of having a see() method in the dog class which takes an Animal argument and then checks the actual type of the object (frog, cat etc) and takes the required action - play, chase etc depending on the actual type. However this would require RTTI which must be bad design. Can anybody please suggest a better design which would avoid RTTI and also point out the mistake in my thinking?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用“OO 概念”来解决这个问题的方法有很多,具体取决于您想要强调的内容。
这是我能想到的最简单的解决方案:
如果您需要多种“感知”动物,可以直接为
see
制作一个虚拟包装器(生成 双重调度):上面要求
Animal
类了解一些关于这Buddy
类。如果您不喜欢您的方法是被动动词,并且希望将Animal
与Buddy
分离,您可以使用访问者模式:第二种机制可以用于除巴迪看到了一只动物(可能是那只动物看到了巴迪)。然而,情况更为复杂。
请注意,OO 绝对不是解决这个问题的唯一方法。对于这个问题,存在其他可能更实用的解决方案,例如存储导致 Buddy 吠叫、进食、玩耍等的各种动物的属性。这另外将
Buddy
类与解耦。 >Animal
类(即使是访问者模式也需要 Buddy 可以感知的所有内容的详尽列表)。There are a ridiculously large number of ways to satisfy this problem using "OO concepts," depending on what you want to emphasize.
Here's the simplest solution that I can come up with:
If you need multiple kinds of "perceiving" animals, it's straightforward to make a virtual wrapper for
see
(producing a form of double dispatch):The above requires that the
Animal
class know something about theBuddy
class. If you don't like your methods being passive verbs and want to decoupleAnimal
fromBuddy
, you can use the visitor pattern:The second mechanism could be used for purposes other than Buddy seeing an animal (possibly for that animal seeing Buddy). It is, however, more complicated.
Note that OO is definitely not the only way to solve this problem. Other solutions exist that may be more practical for this problem, such as storing the properties of the various animals that cause Buddy to bark, eat, play, etc. This additionally decouples the
Buddy
class from theAnimal
class (even the visitor pattern needs an exhaustive list of everything that Buddy can perceive).该设计特别要求识别某些实体以便对它们执行某些操作。因为关于为什么某些操作与某些实体一起使用没有押韵或原因(即:它都是任意的),所以您所看到的要么是基于类型的调度,要么是基于属性的调度。我会选择后者。
给每个实体一些属性。因此,狗会根据这些特性做出反应。猫和松鼠将拥有“狗应该对我吠叫”的属性。当狗遇到具有这种属性的实体时,它会执行适当的操作。
在这种情况下,一个实体只不过是其属性以及基于遇到具有各种属性的其他实体的行为的总和。该实体还可能具有与其关联的某种状态。不会有特定的狗或猫类别。只会有一个具有类似猫的属性和行为的实体,以及一个具有类似狗的属性和行为的实体。
The design specifically calls for recognizing certain entities in order to perform certain operations on them. Because there is no rhyme or reason with regard to why certain operations go with certain entities (ie: it's all arbitrary), what you're looking at is either type-based dispatch or property-based dispatch. I'd go with the latter.
Give each entity some set of properties. The dog would thus react based on those properties. Cat and Squirrel would have the property, "Dog should Bark at me." When the Dog encounters an entity with such a property, it would perform the appropriate action.
In this case, an entity is nothing more than the sum of its properties as well as the behaviors based on encountering other entities with various properties. The entity may also have some state associated with it. There would not be a specific Dog or Cat class. There would just be an entity with Cat-like properties and behaviors, and an entity with Dog-like properties and behaviors.
提示:使用虚拟函数(在目标动物上)而不是 RTTI。
Hint: use virtual functions (on the target animals) instead of RTTI.
大多数时候,您可以通过消息传递来替代 RTTI。
原则上, Sort of
Messaging 比 RTTI 更灵活:
因为它允许设计目前未知的关系。假设明天你的狗将看到在其他 DLL 中定义但在 Pascal 中定义的 racoon。
Most of the time you can replace RTTI by messaging.
Sort of
Messaging is more flexible than RTTI in principle:
as it allows to design relationships that are unknown at the moment. Say tomorrow your dog will see racoon that is defined in some other DLL and yet in Pascal.