Jump to content
  • Advertisement
  • entries
    146
  • comments
    436
  • views
    198529

Singletonitis, Part 2

Sign in to follow this  
Washu

354 views

The Singleton Pattern's intent is to "ensure a class only has one instance, and provide a global point of access to it." [DP, p. 127]

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.
Sign in to follow this  


7 Comments


Recommended Comments

pfft.. you think Singletons are the result of bad refactoring? Take a look at this! Yeah, that's right. That was refactored once. Guess it's gonna take at least ∞ passes at this piece of crap code base before its actually workable...

Rawr. Making work for tommorrow today. [grin]

Share this comment


Link to comment
I realize this may be ignorant, but I just have to ask - what would be a case for a singleton ? You have - in brutal fashion - destroyed the basis for almost all uses of the singleton pattern as it relates to game developement. The last bastion of defence, per se, lies in it's easy applicability for memory management or messaging schemes. But even that just seems like lazyness (i.e. Enginuity, signals and slots) ... so is the singleton applicable in any type of gamedev related task ?

Share this comment


Link to comment
Ok I am going to refactor now.

Oh yeah, you not only make babies cry you make me cry too.

Share this comment


Link to comment
@stormrunner
the only case for a singleton i can think of is a logging system, where it could be argued that you do need only one and global access to log from anywhere.

I now await Washu to shoot that arguement down [wink]

Share this comment


Link to comment
What if I plan to make a singleton that will be used in other applications (albeit with one instance and global access)? Isn't the point of an OO language to provide encapsulation and code that is reuseable?

*ducks*

Share this comment


Link to comment
Maybe I am missing some important point here and if so then please tell me, but in my opinion most of the arguments in this article are false.

Quote:

Argument: the singleton pattern makes the class globally visible which pollutes the global namespace.

Why must a singleton be in the global namespace whereas other objects do not have to be? A singleton is as globally available as any other type.

Quote:

Argument: the programmer cannot guarantee that multiple instances are created.

Not true. If the constructor is inaccessible and the GetInstance() function returns only the same instance, it is guaranteed that only one instance exists. The only glitch is thread safety which goes for all functions.

Quote:

Argument: global access is only waranted for classes that are used in a great part of code.

This means that whenever the size of code change, a smaller portion may be using the singleton. So when writing many lines of non-singleton code, suddenly the singleton is no longer warranted? What about future use of the singleton class in this or other projects?

Quote:

Argument: anyone can change the state of an object making it intractible.

This goes for any object. As long as the member functions are safe in this sense the state of the object is secured.

Again maybe I am totally besides some point here. And now its time to really duck for me too I guess. ;-)

Greetz,

Illco

PS: quotes are not literally but an extraction made by me

Share this comment


Link to comment
Maybe I shouldn't reply to a thread that has been dead for two years, but here goes...

Quote:
Original post by Illco
Why must a singleton be in the global namespace whereas other objects do not have to be? A singleton is as globally available as any other type.

The problem with singletons is not that they're global as such - it is that they have global state. This means that there will be a multitude of places in your code that access, and maybe even modify global variables. This is a maintenance nightmare, especially in the later case. If your singleton doesn't have (mutable) state, you're safe (because, well, it's not a singleton then).

Monostates are exactly as bad, since they provide the kind same access to global mutable state. Actually they are worse, since it's not obvious that they share state.

Classes on the other hand, do not have state. Only instances do, and those are not global (they have to be explicitly passed around as arguments).

Note that if you look at everything in your class that is declared "static" in isolation, you are looking at a singleton. If it has mutable state, you're probably in trouble.

My own rule is: don't make static variables, and don't make static constants that reference mutable objects. Note that this also excludes singletons. There really aren't that many exceptions.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!