Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've heard countless times about the pitfalls of Singletons / globals, and I understand why they're so often frowned upon.

What I don't understand is what the elegant, non-messy alternative is. It seems that the alternative to using Singletons/globals always involves passing objects a million levels down through your engine objects until they reach the objects that need them.

For example, in my game, I preload some assets when the game starts up. These assets aren't used until much later when the player navigates through the main menu and enters the game. Am I supposed to pass this data from my Game object, to my ScreenManager object (despite the fact that only one Screen actually cares about this data), then to the appropriate Screen object, and anywhere else?

It just seems that I'm trading global state data for cluttered dependency injection, passing data to objects that don't even care about the data except for the purpose of passing it on to child objects.

Is this a case where a Singleton would be a good thing, or is there some elegant solution I'm missing?

share|improve this question

4 Answers 4

up vote 13 down vote accepted

Don't conflate singletons and globals. While some kind of global variables are usually necessary, the singleton is not just a replacement for a global variable, but primarily a way to work around problems of static initialization order in C++ (and FQA). (In other languages, it's a way to work around different language deficiencies, like the lack of global variables and bare functions.)

If you can just use a global pointer instead of a singleton, and make sure it's initialized (manually) before anything needs it, you avoid the function call and branch overhead, the lame syntax to get at the object, and you can actually make a second instance of the class when you need to for tests or because your design changed.

For the few global variables you want (common examples being audio output, list of open windows, keyboard handler, etc.), I recommend the service locator pattern. It makes it easy to replace things with different implementations (e.g. real vs. null audio device), and collects all your globals into one structure to avoid polluting your namespace.

share|improve this answer
    
+1! Very nice pattern! –  jwueller Nov 13 '10 at 19:19
    
+1. Good answer and thanks for the service locator pattern link. That's a very interesting read. –  bummzack Nov 16 '10 at 13:07

If you don't/can't have one part of the code magically "know" about some data, then it will need to be passed in somehow. However that doesn't mean it must necessarily by passed only through arguments.

In your example case, could you not have some kind of "AssetManager" which would load and store the assets, and then the ScreenManager would only need to be given a reference to that (probably at creation)? In that sense you're passing the references to the assets wrapped up in another object, and you can pass that once, at initialisation, rather than pass it down to the leaf function when it's required.

Now IMHO that AssetManager, being the kind of thing you only want one of, might as well be a singleton. Provided you understand the pitfalls, and code specifically to avoid them (assume that singleton will be accessed simultaneously from multiple threads and stab yourself with a fork any time you do something that needs to block), then knock yourself out.

share|improve this answer

I think Jason D is absolutely right - this is how I would handle it:

Game has an instance of AssetManager, an object from which you can get any asset by name.

In Game:

assetManager = new AssetManager();
screenManager = new ScreenManager();
screenManager.assetManager = assetManager;

In ScreenManager:

screen = new Screen();
screen.assetManager = assetManager;

In Screen:

myAsset = assetManager.getBitmp("lava.png");

Now all screens have access to any assets they need. This is not any more complex or crazy than using globals or Singletons, and you have an option of having 2 instances of Game running in the same application without clashes. I once had to make a game that was made up of 8 mini-games, all sharing the same base classes / framework. I had to refactor all my globals/singletons to use this reference passing style, and I've never looked back. The only things that should be globals are things that can only physically exist once, such as audio, networking, i/o etc.

share|improve this answer

You could use the Factory pattern to replace Singleton. Then the factory class has the control over how many instances you can create, which you can easily change later when you find you need more than one AssetManager. As stated in this article:

It gives you all of the flexibility of the Singleton, with nowhere near as many problems.


Another, rather limited, possibility is to make the class static (which I don't think is feasible for an AssetManager and only possible in languages that have static classes at all). But that works only if you don't need inheritance/polymorphism. It's a very inflexible solution:

static methods are as flexible as granite. Every time you use one, you're casting part of your program in concrete. Just make sure you don't have your foot jammed in there as you're watching it harden. Someday you will be amazed that, by gosh, you really DO need another implementation of that dang PrintSpooler class, and it should have been an interface, a factory, and a set of implementation classes. D'oh!

This is about static methods, but it can be applied to static classes, too.

share|improve this answer
    
What do you mean by "make the class static"? C++ doesn't have static classes. Do you mean only have static methods? Why bother having a class instead of a namespace then? –  user744 Nov 13 '10 at 11:53
1  
@Joe: Well, the question is not focused on C++ as I understood it. In C# or Java you can make static classes and I'am referring to those. Also, as I said, static classes aren't an optimal solution most of the time, but in rare cases it could work like a global. –  Michael Barth Nov 13 '10 at 13:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.