C++ 正确的单例用例

C++ proper singleton use case

我正在制作一个游戏来练习好design/arch,我想我已经将自己编程为一个支票。我不确定我的架构现在是否干净,一些建议很重要。

我有一个 class Game 包含 class GraphicsManager class InputManagerclass StateManager

的实例

图形管理器像输入管理器一样处理 sdl 内容。状态管理器是一堆抽象类型 class GameState

每一帧,游戏都会在状态堆栈顶部的 GameState 上调用更新,并向所述状态传递一个 StateManager 指针,以便 GameState 可以推送新状态或从堆栈中弹出自身。

GameState* currentState = stateManager.getState() //return top currentState.update(&stateManager) // state might change here

问题是当我介绍我的 class Screen 时。 Screen 应该由 GameState 的各种实现拥有,所以如果我有 OpeningState,我希望它拥有 OpeningScreen。 问题是,Screen 需要访问 Graphics 实例以获取指向 SDL_Renderer 的指针,但我看不到向下传递该指针的好地方。从 Game --> GameState --> Screen 传递指针感觉有点古怪。

我觉得我需要将每个 'Manager' 变成一个单例,但如果有更优雅的东西我很想学习

这是我的参考代码 https://github.com/MicahMartin/FightingGame/tree/master/src

您可以使用单例而不是显式注入依赖项,但请注意,这种设计会导致代码的可测试性降低和组件之间的功能耦合度高。其他生态系统已经解决了这个问题,引入了以声明方式注入依赖项的方法,这要归功于提供用 "test doubles" 替换实际依赖项的机制的框架。查看 Spring MVC 如何与 Java 应用程序一起工作。

如果您确定这是您所需要的,您可以使用类似(但仍然不太灵活)的方法来实现 "service locator" 模式,该模式包含一个点,该点包含指向 "injectable" 个对象

ServiceLocator::inject<Screen*>(new Screen () , "screen1")

//

...

//
Screen* s = ServiceLocator::getInstance<Screen*>("screen1")

这样可以避免传递指针,同时可以更加解耦。现在假设您有一个继承自 Screen 的 MockScreen。还假设您要测试方法 int MyClass::workWithScreen(),它依赖于用标签 "screen1" 引用的 Screen 实例。您可以像

这样编写测试
Myclass unitUnderTest;
ServiceLocator::inject<Screen*>(new MockScreen () , "screen1");

int result = unitUnderTest.workWithScreen()

assert ....

我将留给您作为实施服务定位器的练习!

请记住,通过这种方式,您也在代码中引入了依赖注入的缺点:其中最糟糕的是您失去了对组件布局设计的控制,每个对象都可以访问每个对象目的。当您开发一些基于可靠且众所周知的架构模式(控制器 -> 服务 -> 存储库 -> 数据库 然后返回)的 REST api 处理程序时,这不是一个大问题,但你必须小心在其他情况下!