正确使用和实现单例

时间:2012-12-07 07:23:48

标签: c++ multithreading singleton

我正在编写一个多线程游戏结构。我下面的内容是基本结构。 EventManager,LogicManager和Renderer都是线程。它们从通用的Gamestate类读取/写入,它将处理线程之间的所有共享资源。根据我的理解,Gamestate在技术上应该是一个单身人士。那是对的吗?我还想知道如何将其实现为“早期初始化单例”,如下所述:http://www.oodesign.com/singleton-pattern.html#early-singleton,但在C ++中除外。我担心我不太熟悉C ++静态,因此我不知道在哪里放置“private static Singleton instance = new Singleton();”用C ++编写的。我知道我可以通过一种解决方法获得相同的效果,但我想以这种方式尝试。

int main(){
    Gamestate gs;
    EventManager em(&gs);
    LogicManager lm(&gs);
    Renderer renderer(&gs);

    lm.start();
    renderer.start();
    em.eventLoop();

    return 0;
}

2 个答案:

答案 0 :(得分:1)

正如@juanchopanza和@Dietmar评论的那样,游戏状态真的没有理由成为单身人士。

此外,我可以想到为什么成为一个原因的几个原因:

  1. 单身人士对单元测试非常困难。模拟单例而不是界面要困难得多。

  2. 假设有一天你想扩展你的游戏?例如,如果有一天你想让游戏逻辑在服务器上运行并让你的玩家运行客户端(想多人游戏)怎么办?在这种情况下,您可能希望在您的流程中拥有多个游戏状态,并且单例限制您不必要。

  3. 如果您想对游戏状态进行操作,例如将其序列化以在机器之间发送,或者可以从文件中保存并加载它,那么将游戏状态设置为单例会使其变得更加困难。使用标准序列化框架变得很麻烦。

  4. 很难将依赖关系注入单身人士。如果您需要一些组件或数据来初始化游戏状态,该怎么办?在这种情况下,即使某个线程处于不一致状态,您也会有一段时间可以访问游戏状态实例。

  5. 我可能会想到更多的理由。无论如何,我的建议是为所有组件定义接口,并让每个组件接收它作为构造函数参数作为接口所依赖的组件。

    这样可以更容易地编写分离良好的类,防止类膨胀,并进行良好的单元测试。

    然后你可以使用任何控制框架的反转来自动神奇地将所有组件绑定在你的游戏初始化代码中。

答案 1 :(得分:1)

如果您绝对需要全局游戏状态对象,请将其设为全局。将其声明为全局(智能)指针,在main的开头手动初始化它,并在最后手动销毁。通过这样做你

  1. 避免多线程问题
  2. 完全控制你的单身人士被初始化和销毁​​的顺序
  3. 为单元测试注入模拟对象很容易
  4. 当其他人指出时,单身被高估到了反模式的程度。避免。