如何管理一组派生但不相关的类

时间:2009-11-12 01:47:14

标签: c++ design-patterns oop aggregation

我越了解这个问题就越能理解。我认为我之前的问题没有传达我正在努力做的事情。我为此道歉。

在我的设计中,我有GameObjects,它本质上是一个聚合类,GameObject中的所有功能都是通过添加各种“功能”来实现的。 Feature是Feature类的子类,它具有自己的成员和函数。所有功能都可以接收消息

class Feature
    {
    public:
        virtual void takeMessage(Message& message) = 0;
    };

class VisualFeature : public Feature
    {
    public:
        void takeMessage(Message& message);
    private:
        RenderContext m_renderer;
    };

... Additional Features ...

FeatureServers是负责协调各种功能的对象。 GameObjects可以订阅FeatureServers来接收来自它们的消息,而Features可以订阅GameObjects来处理它感兴趣的消息。

例如,在此代码中:

GameObject Square;
VisualFeature* SquareSprite = new VisualFeature();
Square.subscribe(SquareSprite, "MESSAGE_RENDER");
Square.addFeature(SquareSprite);
m_VisualFeatureServer.subscribe(Square, "MESSAGE_RENDER");

VisualFeatureServer发送绑定到“MESSAGE_RENDER”的消息,该消息可能看起来像这样

class Message
    {
    public:
        std::string getID() {return m_id;}
        bool isConsumed() {return m_consumed;}
        void consume() {m_consumed = true;}
    protected:
        bool isConsumed;
        std::string m_id;
    }

class Message_Render : public Message
    {
    public:
        Message_Render() : m_id("MESSAGE_RENDER"), m_consumed(false) {}
        RenderTarget& getRenderTarget() {return m_target;}
    private:
        RenderTarget& m_target;
    };

当VisualFeatureServer将Message_Render类发送到Square GameObject时,它会将其转发给订阅接收该特定消息的任何FeatureComponents。在这种情况下,VisualFeature类接收Message_Render消息。这就是我的问题所在,VisualFeature类将接收一个Message&它可以告诉它是一个Message_Render它的ID,我希望能够将它视为Message_Render而不是像这样的消息:

void VisualFeature::takeMessage(Message& message)
    {
    //Here's the problem, I need a pattern to handle this elegantly
    derivedMessage = convertMessageToDerivedType(message);
    this->handleDerivedMessageType(derivedMessage);
    }

void VisualFeature::handleDerivedMessageType(Message_Render& message)
    {
    message.getRenderTarget().render(m_renderer);
    message.consume();
    }

有没有办法优雅地处理这种设计的takeMessage部分?

4 个答案:

答案 0 :(得分:1)

我不确定我是否真的理解你的问题,我认为你需要澄清你想要达到的目标。

只是其他一些评论。

我不认为公共继承(如您所实现的)是这里使用的最佳设计模式。具有公共继承的黄金法则是,只有在派生的类真正“是基础类的对象时才应该使用它。

在C ++中使用继承的一个主要好处是实现多态,其中(例如)你有一个指向Base对象的指针列表,你可以在这些对象上调用方法,并根据需要将它们发送到相关的VisualComponentPhysicsComponent对象方法。

由于(用你的话说)他们有“不相关的类接口”,你将无法获得多态性的任何好处。

听起来你真的从Base类继承来实现Mixin模式。

也许合成是更好的方法,您可以在BaseVisualComponent类中包含PhysicsComponent类(您必须重命名)的副本。

但是,基于以下问题:

  

如果我只有引用或指针   根据我的设计选项   暴露界面   VisualComponent还是PhysicsComponent?

GameObject类(你在main()中实例化)是不是已经为你做了这个?


修改

好的,我想我现在已经对这个问题进行了编辑了解得更好。

  

但我需要一些方法来存储所有   动态组件中的组件   GameObject但仍然可以使用   他们各自的接口。

我能看到这个工作的唯一简单方法是在virtual中创建一个Base方法,该方法在每个派生类中被重写并实现特定于类的行为。 GameObject可以简单地存储Base指针的容器,并调用将被派遣到派生类的virtual方法。

我还建议您制作Render()Move()和任何非虚拟方法private,以便GameObject课程只能访问公众(virtual ) 方法。这有助于保持公共界面的清洁。

我不确定这是否有帮助。


编辑2:

在评论中进一步讨论之后,听起来factory patternabstract factory pattern就是您所需要的。

答案 1 :(得分:1)

另一个答案是编辑过于膨胀,所以我开始了一个新的。

你在receiveMessage()函数中进行的转换绝对是代码味道。

我认为你需要结合使用:

这个想法是每个组件类型只订阅自己类型的消息,因此只接收用于它的消息。这样就不需要铸造了。

作为示例,通知对象可以使用由消息ID索引的通知对象的向量。观察对象(派生组件类)可以订阅由其自己的消息ID索引的特定通知程序。

您认为这种设计模式会有所帮助吗?

答案 2 :(得分:0)

访客模式。如果我明白你在问什么。

虽然真的需要了解更多背景信息!

答案 3 :(得分:0)

查看boost.signals

您可以为每种消息类型定义一个信号,并允许功能向其添加插槽(接收器),这可能是其任何名称的成员函数,或任何其他具有适当签名的可调用内容。