1

似乎我越是谈论这个问题,我就越了解它。我认为我之前的问题没有传达我想要正确做的事情。对此我深表歉意。

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

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 类将收到一条消息,它可以通过它的 ID 判断是 Message_Render,我希望能够将其视为 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

4 回答 4

1

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

不过只是其他一些评论。

我不认为公共继承(如您已实现的那样)是此处使用的最佳设计模式。公共继承的黄金法则是,只有在派生类真正“是”类的对象时才应该使用它。

在 C++ 中使用继承的主要好处之一是实现多态性,其中(例如)您有一个指向Base对象的指针列表,您可以调用这些对象的方法,并将它们分派给相关的VisualComponent对象PhysicsComponent方法。

因为(用你的话来说)它们有“不相关的类接口”,你不会得到多态性的任何好处。

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

也许组合是更好的方法,在or类中包含类的副本Base(您必须重命名)。VisualComponentPhysicsComponent

但是,基于以下问题:

如果我只有一个引用或指向 Base 的指针,我必须公开 VisualComponent 或 PhysicsComponent 的接口吗?

GameObject类(您正在实例化的)不是main()已经为您做这件事了吗?


编辑:

好的,我想我现在已经更好地理解了这个问题。

但我需要一些方法将所有组件动态存储在 GameObject 中,但仍然能够使用它们各自的接口。

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

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

我不确定这是否有帮助。


编辑2:

在评论中进一步讨论后,听起来像工厂模式抽象工厂模式是你需要的。

于 2009-11-12T01:57:29.980 回答
1

另一个答案是编辑太臃肿,所以我开始了一个新的。

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

我认为您需要使用以下组合:

这个想法是每个组件类型将只订阅它自己类型的消息,因此只会接收为其指定的消息。这应该消除铸造的需要。

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

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

于 2009-11-12T04:32:51.977 回答
0

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

虽然真的需要知道更多的背景!

于 2009-11-12T01:57:03.387 回答
0

看看boost.signals

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

于 2009-11-12T06:49:54.477 回答