逻辑设计模式

时间:2009-03-23 15:09:32

标签: c++ design-patterns logic

在游戏中,每帧都应更新许多实体。我玩弄不同的设计模式来实现这一目标。到目前为止,Ive有一个单例管理器类,每个逻辑实例都添加到该类中。但我考虑以下,Logic类本身的静态列表。这很好,因为它会从项目中删除一个类。此示例中的“Engine”将是调用update_all的主类。

class Logic
{
public:
    Logic() { all.push_back(this); }
    virtual ~Logic() { all.erase(this); }
    virtual void update(float deltatime) = 0;

private:
    friend Engine;
    static std::list<Logic*> all;
    static void update_all(float deltatime)
    {
        for (std::list::iterator i = all.begin(); i!=all.end(); ++i)
            (*i)->update(deltatime);
    }
};
  • 这个模式有名字吗?
  • 你认为这比单身经理人课更好吗?
  • 还有其他意见或警告吗?

6 个答案:

答案 0 :(得分:2)

您也可以将observer pattern用于此

答案 1 :(得分:2)

首先,您需要使用remove()而不是erase()(后者需要迭代器作为参数)

如果使用稍微不同的循环,如

std::list<Logic*>::iterator it = all.begin();
while (it != all.end()) {
  Logic* current = *it;
  ++it;
  current->update(deltatime);
}

您甚至可以解决提到的 siukurnin 问题(在update()期间删除Logic对象)。除了指向已删除元素的迭代器之外,list::remove()不会使迭代器失效。

除此之外,我还投票支持这是单身人士模式的变体。我建议将原始解决方案与单独的管理类保持一致,以防万一你需要有两个不同delta时间的循环或显式多线程支持(不同线程上的不同Logic对象)或将来的任何东西。

在我看来,这是单例类相对于静态方法的一般优势(你可以随时使用):如果你想在未来这样做,你可以轻松地增加你的功能......

答案 2 :(得分:1)

我认为它仍然是单身:“只能有一个”

单身是一种模式,一种概念:你可以用不同的方式实现它......

静态类成员或全局实例是同一想法的两种可能实现。

问题是:你为什么要改变它?

答案 3 :(得分:1)

Imho,它是一个Observer模式(cfr update调用每个订阅者),其中Subject恰好是Singleton。

更新观察员时取消注册的“警告”很难。我发现自己经常多次挣扎。

关于这个问题的优雅解决方案在this answer中暗示我的问题:对于每个观察者,添加一个包含指向“真实”观察者的指针的中间“代理”。取消注册相当于交换(原子地)代理的指针。更新后,可以安全地删除所有带空指针的代理。

答案 4 :(得分:1)

通常,您希望在每个更新调用中浏览游戏中的每个实体,因此您可以继续使用Composite pattern,其中您有一个根节点。从那里,您将递归遍历节点并调用每个实体的update()方法。从我在代码中看到的内容,您已经有了一个列表,但是使用复合模式,您可以创建实体组,这可以简化您的任务。

据我所知,您的引擎只需要调用根节点的Update()方法(如果使用复合模式)。从那以后,根节点将使用他们的update()调用后续节点。在某些时候,通过复合树,您将获得知道如何正确更新自己的叶子。

您只需要在引擎中有一个指向根节点的指针,该指针将具有一个函数UpdateAll()(或其他东西),然后调用rootNode-&gt; Update();反过来,它将完成我在前一段中描述的内容。

答案 5 :(得分:0)

有一点需要注意,这个模式(当前)不允许在调用update_all期间删除Logic实例,因为它会使迭代器指针无效。

解决方案可能是让析构函数变为私有并让更新返回一个标志,说明是否应删除该实例?