It would seem that many people forget that the pattern embodies the whole definition there. Many "Singletons" are Singletons for no other reason than to take advantage of only a single property of the Singleton pattern. Using the examples listed previously, we'll continue from there.
Input Manager:
This is perhaps the biggest offender. The only reason it is a Singleton at all is because the programmer wanted to guarantee that only a single instance was created. Of course, this means that the programmer has conveniently tossed out half of the definition. The problem here, though, is one of visibility. In the tireless efforts of the programmer to prevent others from abusing the code, they have introduced an even worse exploit. The input manager is now globally visible. So how can the programmer guarantee that multiple instances of the object won't be created? Quite simply, you don't. Instead you handle the errors and throw the appropriate exception. Then in your documentation you CLEARLY indicate that only a single instance should be created.
Sound Manager:
This one is less of an offender than the input manager, but still pretty serious. The only reason it has been made a Singleton is to make it a global. Again, the programmer has tossed out half of the definition. First of all, we find that the sound manager doesn't actually require a global scope. The actual amount of code that uses it is fairly small. By applying refactoring techniques we can move these bits of code out to the appropriate subset of classes. Thus the visibility of the sound manager is reduced in scope from a global to a local. The real question is though: Why was this a Singleton in the first place, instead of a global? The simple answer is: The programmer wanted a global. However, he felt guilty about using an out and out global. So he took the next logical step, and wrapped it up in an object, thus he "OOified" it. The problem is, his solution isn't object oriented at all. In fact, it's very much not an object oriented solution.
Graphics Manager:
This one is the one true legitimate Singleton. The programmer wanted an object with only a single instance and a global point of access. However, just like the previous two, there is an issue of visibility. The graphics manager will be used in only a tiny subset of the overall code. While that code might be scattered all over the place, it is none the less, a small portion of the overall code (If it is otherwise, then you are probably writing a graphics engine, and not a game).
Avoiding Singletons:
So what is the real problem with Singletons? To quote Kent Beck: "The real problem with Singletons is that they give you such a good excuse not to think carefully about the appropriate visibility of an object." [Joshua, p. 116]
Remember, a Singleton is a global object. Once an object has been made into a Singleton, it's state can no longer be guaranteed, nor easily tested. Anyone can, and will, go in and change the state of the object.
So, how does one avoid Singletons? Simple, you apply refactoring [RF]. By refactoring your code you can do two things: The first is that you simplify the code. This makes it easier to maintain, extend, read, and reduces duplication. The second thing that you accomplish is that your code ends up being much more object oriented, and the visibility of objects becomes much clearer. Thus if you refactor your code then you can centralize the code that uses an object (that is a Singleton) and remove the need for it to have global visibility. Instead it goes from being a global to being a local or member variable. Where you can't centralize the code, pass the object via parameters, or parameter objects [Joshua].
Now, I am not saying that you shouldn't use the Singleton pattern. Instead I'm saying that you should very carefully consider the implications of making an object a Singleton. You should examine if the object really requires global visibility, or if you are just using it to get around a poor design. If it's the latter, then refactor the design to clean it up. In the words of Martin Fowler: "remember that any global data is always guilty until proven innocent." [PEAA, p. 482-483]
References
[DP] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design
Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley
Professional, 1995, ISBN 0-201-63361-2.
[RF] Martin Fowler, Refactoring: Improving the Design of Existing Code,
Addison-Wesley Professional, 2000, ISBN 0-201-48567-2
[PEAA] Martin Fowler, Patterns of Enterprise Application Architecture,
Addison-Wesley Professional, 2003, ISBN 0-321-12742-0
[Joshua] Joshua Kerievsky, Refactoring to Patterns, Addison-Wesley Professional,
2005, ISBN 0-321-21335-1.
Rawr. Making work for tommorrow today. [grin]