在OO设计中避免RTTI

vja*_*n27 10 c++ oop rtti

我最近在某个论坛上看到了一个OO设计问题,并开始考虑使用RTTI.然而,这一定是糟糕的设计,但我无法想到另一种选择.这是一个简单的问题:

使用OO概念为以下场景创建C++程序 -

我的名叫巴迪的狗住在后院.晚上,当他看到一只猫或一只来看望的松鼠时,他会吠叫.如果他看到一只青蛙,并且他饿了,他就会吃掉它.如果他看到一只青蛙并且他不饿,他就会玩它.如果他已经吃了2只青蛙,并且仍然感到饥饿,他会放手.如果他看到一只土狼,他会求助.有时他的朋友Spot停了下来,他们互相追逐.如果他看到任何其他动物,他只是看着它.我希望你会有一个动物类,一只猫,狗,松鼠,土狼类继承自动物类.

我开始考虑在dog类中使用一个see()方法,该方法接受一个Animal参数然后检查对象的实际类型(青蛙,猫等)并采取所需的操作 - 根据实际类型进行游戏,追逐等.然而,这将需要RTTI,这必须是糟糕的设计.任何人都可以建议一个更好的设计,这将避免RTTI,并指出我的想法中的错误?

Joh*_*eek 13

根据您想要强调的内容,使用"OO概念"来满足此问题的方法有很多种.

这是我能提出的最简单的解决方案:

class Animal {
public:
    virtual void seenBy(Buddy&) = 0;
};

class Buddy {
public:
    void see(Cat&)      { /* ... */ }
    void see(Squirrel&) { /* ... */ }
    // ...
};

class Cat : public Animal {
public:
    virtual seenBy(Buddy& b) { b.see(*this); }
};

class Squirrel : public Animal {
public:
    virtual seenBy(Buddy& b) { b.see(*this); }
};

// classes for Frog, Coyote, Spot...
Run Code Online (Sandbox Code Playgroud)

如果你需要多种"感知"动物,那么制作一个虚拟包装器see(生成一种双重调度形式)是很简单的:

// On a parent class
virtual void see(Animal&) = 0;

// On Buddy
virtual void see(Animal& a) { a.seenBy(*this); }
Run Code Online (Sandbox Code Playgroud)

以上要求Animal班级了解Buddy班级.如果你不喜欢你的方法是被动动词和希望分离AnimalBuddy,你可以使用访问者模式:

class Animal {
public:
    virtual void visit(Visitor&) = 0;
};

class Cat : public Animal {
public:
    virtual void visit(Visitor& v) { v.visit(*this); }
};

class Squirrel : public Animal {
public:
    virtual void visit(Visitor& v) { v.visit(*this); }
};

// classes for Frog, Coyote, Spot...

class Visitor {
public:
    virtual void visit(Cat&) = 0;
    virtual void visit(Squirrel&) = 0;
    // ...
};

class BuddyVision : public Visitor {
public:
    virtual void visit(Cat&)      { /* ... */ }
    virtual void visit(Squirrel&) { /* ... */ }
    // ...
};

class Buddy {
public:
    void see(Animal& a) {
        BuddyVision visitor;
        a.visit(visitor);
    }
};
Run Code Online (Sandbox Code Playgroud)

第二种机制可以用于Buddy看动物以外的目的(可能是看到Buddy的动物).然而,它更复杂.


请注意,OO绝对不是解决此问题的唯一方法.存在对于这个问题可能更实用的其他解决方案,例如存储导致Buddy吠叫,吃饭,玩耍等的各种动物的属性.这另外将Buddy类与Animal类分离(即使访问者模式需要详尽的列表) Buddy可以感知到的一切.


Nic*_*las 6

该设计特别要求识别某些实体,以便对它们执行某些操作.因为某些操作与某些实体的关系没有押韵或理由(即:它都是任意的),你所看到的是基于类型的调度或基于属性的调度.我会选择后者.

为每个实体提供一组属性.因此,狗会根据这些特性做出反应.猫和松鼠会有财产,"狗应该咆哮我." 当狗遇到具有这种属性的实体时,它将执行适当的操作.

在这种情况下,实体只不过是其属性的总和以及基于遇到具有各种属性的其他实体的行为.该实体也可能有一些与之相关的州.不会有特定的狗或猫.只有一个具有类似猫的属性和行为的实体,以及一个具有类似狗的属性和行为的实体.