C ++正确的单例用例

时间:2019-01-23 13:03:34

标签: c++ oop architecture stl singleton

我正在做一个练习良好的设计/架构的游戏,我想我已将自己编程成一张支票。我不确定我的体系结构现在是否干净,请教一些建议。

我有一个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->屏幕传递指针感觉很时髦。

我觉得我需要将每个“经理”变成一个单例,但是如果有更优雅的东西,我想学习

这是我的编号为https://github.com/MicahMartin/FightingGame/tree/master/src的意大利面条

1 个答案:

答案 0 :(得分:1)

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

如果确定这是您所需要的,则可以使用类似(但仍不太灵活)的方法来实现“服务定位器”模式,该模式包含一个指向“可注入”对象实例的指针的点

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处理程序时,这不是一个大问题(控制器->服务->存储库-> db,然后返回),但是在其他情况下您必须要小心!