I woke up this morning to a discussion on Twitter over how different implementations of the Singleton pattern compare. This is like comparing your Herpes: no matter whose is better or more efficient, you still have unsightly blisters.
Overview: wtf is a Singleton?
Singleton is one of the software design patterns originally collected in the famous Design Patterns: Elements of Reusable Object-Oriented Software by the “Gang of Four”. They describe the intent of the pattern thus:
Ensure a class only has one instance, and provide a global point of access to it.
The other useful source of design pattern information is Cocoa Design Patterns by Erik Buck and Don Yacktman. In addition to giving examples of Singleton found in the Foundation and AppKit frameworks, this book shows how to implement a Singleton class in Objective-C. The key features are:
- A single access point to retrieve the single instance.
- Initialization of the single instance.
- Protection against accidentally creating another instance or deleting the single instance.
When would you use that?
Well here’s the thing: I won’t say that I “never would” use Singleton, but I will certainly say that it isn’t the most reached-for tool in my belt.
The usual reason is “this class models something of which there is only one thing”. This is the most absurd thing you’ll ever hear. There’s only one print spooler, so surely it must be a singleton. Right, that only works right up until the point where you need two print spoolers. When do you need a second print spooler? I’ll come onto that in the next section.
Similarly, just because there’s one filesystem, doesn’t necessarily mean that you only need one filesystem object. It certainly doesn’t mean you need to enforce there’s only one filesystem object.
Go on then, wise guy, when do you need the second singleton?
When you test the code that uses the first one. You don’t want your unit tests to talk to the real filesystem, or the real database, or the real print spool. You want your unit tests to use a Mock Object, which means they need the second, fake, instance of your filesystem object or whatever.
That’s the real problem with Singleton: often, in your app, it makes sense to provide a shared instance of an object (particularly one that has state relevant to the entire app). However, that’s not the same as requiring that no-one ever create another instance of the object.
So how would you do it, then?
Let’s assume I have a need for an application-wide Framistan instance. I have a couple of options:
- Create the usual +[Framistan sharedFramistan] class method, as Singleton implementers would, but not all that refcount-avoiding cruft that normally goes with it.
- Create the method -[[NSApp delegate] sharedFramistan]. After all, I have a need for an application-wide instance, and that’s where stuff associated with the application lives.
The option I go for depends on whether I think a process needs a shared instance of the class, or whether I think this app does. Usually, the latter option gets implemented first, and I change it later when I come to write the second app that uses the same class.
Either way, when I need to use the shared instance, I use it like this:
[someFrobnicator abdjulateWithFramistan: [Framistan sharedFramistan]];
Passing the shared instance in means that I still get to pass in other instances, for example in a test I can do [testFrobnicator abdjulateWithFramistan: mockFramistan];.
I don’t like that. Does anyone do something different?
Yes, some people solve Singleton…with another Singleton. The mind boggles. Anyway, what these people do is to create a FramistanFacade Singleton whose job is to manage access to the Framistan Singleton. Now your real Framistan can be an honest Singleton class, but clients talk to the (also-Singleton) FramistanFacade class, which decides what instance of what class it wants to talk to itself.
In Objective-C, the FramistanFacade can use message forwarding to act as a Proxy object, hiding the interaction between Façade and real object. Of course, now that you’re managing the real instance behind the Façade, the real class doesn’t need to be a Singleton because a different class is already managing how its instances are used.
Conclusion
The debates over how best to implement Singleton in Objective-C are redundant because the Singleton pattern is never what you need. Often you do need a shared instance of a class, but enforcing that no other instance ever get used it detrimental to testing.
When you do need a shared instance of a class in your app, ensure that you do not close the door to using alternate instances. The need comes up more often than you might expect.
I really see no need to do anything even resembling a Singleton. I just feed in dependencies at object construction time and use them. Everything is constructed either at application startup or in factories constructed at application startup. Works fine.
I’ve been wondering why people feel it needs to be one or the other. In my code, I create a property for the Framistan the object will need. In the accessor, check whether the ivar is nil–if so, return the sharedFramistan (storing it to the ivar will vary case-by-case).
That way, there’s a default behavior that the invoking class doesn’t have to know about when initializing, and any testing code can init, pass the MockFramistan, then invoke.
Yes, this means your object shouldn’t fire off behaviors in the init, but how often is that a good idea, anyway?
Pingback: Tweets that mention On Singleton(s) — Secure Mac Programming -- Topsy.com
What about NSNull? I think that deserves to be a singleton.
Ben, have you seen my previous post, on NSNull as an anti-pattern? NSNull is really a realisation of Flyweight, but because there’s only one possible value for NSNull this means that it ends up looking like a Singleton.
But NSNull is the wrong implementation of Flyweight. As described in the above-referenced post and the paper Kevlin links to in its comments, the Null Object Pattern is a better design than NSNull because it lets you treat your nulls just like real objects. If you do Null Object properly, then it no longer looks like a Singleton, and looks more like a Flyweight instance of the objects you’re really trying to work with.
Juri: indeed. That’s what you end up with if you follow my “construct in the app delegate” design, because the app delegate (or the XIB it’s in) ultimately handles creating everything else so hooks up, one way or another, new objects with things those new objects need. It’s not quite as clear as it would be with something like an inversion-of-control framework but I still haven’t found a pressing need for one.
Hope this isn’t flogging a dead horse, but I think the approach typically used in Cocoa frameworks is programmatically identical but semantically better than the standard singleton pattern — essentially having a means to access a “default” or “standard” object, such as
[NSNotificationCenter defaultCenter]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
This still allows multiple objects, but supports the most common situation of there only being one.
Cheers