Better Than Singleton

The Singleton Pattern is Bad

OK so don’t use the Singleton pattern. Just don’t do it. It’s much better to have your application context or factory decide when to limit a class to a single instance. The classes dependent on that class should have no idea whether or not they’re talking to a singleton, prototype, or whatever.

Maybe I’ll create a Binaritan pattern, in which the system only instantiates two instances of a class. Or if that’s already been done, a Tritarian pattern.

Sharing State

Aside from factories, there is a neat little pattern — I forget what it was called where I read it — where an instantiated class presents a facade around a shared resource. A Singleton would look like this:

public class MySingleton
private static final INSTANCE = new MySingleton();
private MySingleton() { }
private static getInstance() { return INSTANCE; }

private String someGlobalValue = “whoop!”;
public String whoop() { return someGlobalValue; }

The idea of this singleton is to provide shared access to a value that needs to be shared globally. So we make that value a member variable where the class instance is a class variable.

The flip side of this is to make the class a facade around shared data:

public class MyWhoop
private static String someGlobalValue = “whoop!”;
public String whoop() { return someGlobalValue; }

Consumers of this class have no idea that whoop is a shared value. They are just all delightfully pleased to find they all get the same value wherever they reference a member of this class.

MyWhoop whoop1 = new Whoop();
MyWhoop whoop2 = new Whoop();

assertTrue( whoop1.whoop().equals(whoop2.whoop()) )

The advantage is that MyWhoop can be subclassed or mocked and swapped out any time you want to change the behavior for testing in isolation. For example, you could have a class “Querer” that’s responsible for queuing tasks on a shared queue.

public class MyWhoop
private static Queue myQueue = new Queue();
public String enqueue(Task t) { myQueue.push(t); }
public int queueSize() { return myQueue.size(); }

Now any class that instantiates a Queuer finds that, magically, they are enqueing tasks on the shared queue, and that if they watch the queue size from their instance, it just magically grows and shrinks.

Naturally, since the class is built on top of a shared variable, you have to take precautions to make sure access is synchronized or concurrent (i.e. thread-safe). But the facade class can take care of that, and, again, the clients to the class don’t need to worry about it.

I still think that managing shared data between classes is best left to whatever factory or application context is creating everything. But if you really do need something like a singleton that’s handing out references to shared data, then this is a cleaner pattern with fewer of the nasty problems that singleton presents.


Leave a comment

Filed under design patterns, opinionizing, utility

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s