Design Patterns – Alternatives to Singleton for Single Instance Classes

anti-patternscdesign-patternsobject-oriented

I need to represent an abstraction over various parts of the hardware for a game. I'm trying to decouple the code that does things like manage the logic of the game from the code that is API/platform specific or any ugly implementation details.

Like this:

std::unique_ptr<IDevice> device(CreateDevice());

IGraphicsDevice *graphics = device->getGraphicsDevice();
ISoundDevice *sound = device->getSoundDevice();
IWindow *window = device->getWindow();
IJobManager *jobmanager = device->getJobManager();
//etc

One solution I've seen was to simply put all of this as globals and initialize them in main, but I'd like to avoid that if I can because I don't really like dealing with globals (and I find them to be "ugly", for the lack of a better word). I also can't allow more than one instance because it requires initialization of libraries which are globally initialized themselves.

What alternatives to the singleton pattern are there for this?

I know that more than one instance would likely lead to errors, is this a bad design decision? Could I do anything different?

Best Answer

This is called the Singleton Pattern and is considered to be an anti-pattern by many people nowadays, since it hides dependencies and makes your code less maintainable.

The necessity for using the singleton pattern may arise from other bad design decisions, but I cannot judge since I know nothing about your architecture and design.

Anyway, let me give you an example how to get rid of this pattern. In a game there will most likely be some kind of main loop which calls everything else. For simplicity let's assume this main loop is contained in an object, but this is not a must. When you create the object that contains the loop, you pass the objects you created in your example code (or rather references to them) to that object. It's possible either to pass them via an appropriate constructor or via setter methods to mention the most common examples. How you do this in you main loop strongly depends on your class design, but you'd be able to perform the rendering something like this

while(running)
{
    game_state->update();
    renderer->render_state(game_state);
}

The adventages of this approach are that you eliminate the need for global objects or singletons and avoid that your objects know how to create your device objects. The only thing your objects have to know is that there are some device abstractions they can use. They do not have to know anything else.

This approach is called Dependency Injection and is considered to be a very important pattern of modern OO-design.

Related Topic