Sunday, November 11, 2007

The Evil Mr. Singleton

In my not very humble opinion, the singleton pattern is the worst pattern ever, and the fact that it is discussed in many books that talk about patterns make people think that it's a good thing (which is a flawed thinking). To make matters worse, almost no pattern book talks about why singleton is bad for you. In a way the pattern books out are not unlike that of a phone book - you get a list of phone numbers, but it doesn't tell you the guy who owns the number likes to molest Flash developers and that you should avoid calling the number!

This reminds me of how beginners in OOP would always fall into a "how can I make my code fit into an inheritance model" state of mind.

There are a few reasons why you should never use singleton in your code, and most definitely not in your framework if you happen to write one. Here are some of the reasons I can think of off the top of my little head:

1) The syntax is hideous. There is no way to hide the fact that the object you are dealing with is a singleton.

2) The standard in naming a singleton is non-existent. Different people name the instance accessor differently. I have seen code that use getInstance(), getInst(), instance(), etc.

3) What should you do when you inherit a class that is a singleton?

4) If you are implement this in AS3, you have the additional problem of not being able to declare private constructor to prevent direct object instantiation on your class.

5) It makes your class less tolerant to change in requirements. What if one day someone would like to instantiate multiple instance of your class?

6) Making an object singleton is almost the same act as declaring a global variable. Anyone can access your object from anywhere in your application. This convenience allows you to create unnecessary coupling to your application more easily and irresponsibly.

7) Code that uses singleton must take care of destroying it or resetting it with a custom destroy method where appropriate. For example, if you are implementing a Restart feature for your game, you want to make sure you are getting a brand new copy of the singleton object whenever the game restarted.

8) Most importantly, enforcing the single-ness should not be done at the object level (especially for the ones that can be used across multiple applications). This is inherently a policy-based issue, and should be dealt at the application level (through the use of a policy-based class or passing your objects around), not at the object level.

I sincerely hope you will think twice before you start creating your next singleton. Remember, no one wants to be single forever!

4 Comments:

Blogger Andrew Blair said...

I agree with your points except that I still find that there are one or two exceptions that Singleton can be handy for – or alternatively a static method of a class – in cases where no instance is necessary. I'd like to add another reason why Singleton is evil:

If you get the bright idea to pass arguments to your singleton's constructor you may end up baffled why the arguments aren't taking, only to find out that the singleton was first instantiated somewhere else – ignoring your arguments in subsequent getInstance, because an instance already exists. If you have to use singleton, don't use arguements in the constructor.

My feeling is that singleton should be a last resort, and only used when the alternative options' downsides outweigh the ones listed here. This includes talking with your colleagues about how else you might be able to handle what you want to do.

I do find using a Singleton useful for wrapping a site tracking tagging call, since it gets used in various places throughout a site, throughout multiple swfs. I've tried centralizing the tagging code somewhere and in AS2 manually bubbling the event to that place, but it felt like overkill. I think I'll reconsider in AS3 though in cases where event bubbling won't feel so tedious since it's automated.

There are lots of design patterns, don't fall into the trap of learning one and using it everywhere. "when you've got a hammer everything looks like a nail". Do this with a singleton and you'll be sorry :)

8:22 AM  
Blogger Andrew Blair said...

This post has been removed by the author.

10:50 PM  
Blogger Bruce said...

I'm working on a framework I'm calling SingleGorm. Every class will be a Singleton, derived from the trusty baseclass; AbstractSigleton. I'm building it around the ModelLocator patern, there will be a (singleton) class called SingletonLocator and any class will be accessible like:
SingletonLocator.getInstance().getSingleton("mySingleton");

I'm also adding a static method to empower all classes as singletons using the mixin pattern. Simply call: SingletonUtils.initialize(Object.prototype); to add the handy getInstance() method to all classes.

In my framework even static members will be accessed singleton style, to enable this all singletons (all classes) have a method to access the class; getClass().

eg:
Old:
Math.random();

New:
Math.getInstance().getClass().random();

I'm working on some other singleton stuff I will be posting about soon. Like MultiSingleton, which will allow singleton functionality for classes with multiple instances.

12:14 AM  
Blogger boon said...

@Andrew: Well-said.

@Bruce: LOL!!!

2:57 AM  

Post a Comment

<< Home