Death to the Singleton
January 17, 2008
Even those like myself who haven’t had the occasion to work through Design Patterns should no doubt be familiar with the Singleton Pattern. Though it’s one of the most used software patterns, especially in API’s like the JDK and Cocoa, it’s also attracted its fair share of flak for a myriad array of reasons, chief among them being that they’re simply a global variable with a nice name.
Now, it’s none of my business how you implement your classes, and I’m a member of the school of thought that global variables (especially in scripting languages) are often necessary. What really frosts me about singleton classes is their verbosity. Take, for example, this snippet of Nu code:
(if (((NSFileManager defaultManager) fileExistsAtPath: somePath))
((NSFileManager defaultManager) copyItemAtPath:otherPath toPath:somePath error:nil)
(else
((NSFileManager defaultManager) createDirectoryAtPath: somePath)))`
This is, needless to say, ugly and repetitive. One could create a temporary variable to hold the NSFileManager, but that would not be a remedy for the verbosity associated with singleton classes like this - it’s merely a stopgap measure, and adds more code that you have to read. What I’d really like to do is this:
(if ((NSFileManager fileExistsAtPath: somePath))
(NSFileManager copyItemAtPath:otherPath toPath:somePath error:nil)
(else
(NSFileManager createDirectoryAtPath: somePath)))
that is, have every instance method on the default NSFileManager become a class method. Were I totally brain-dead, I would declare an extension to NSFileManager and create a class method for every instance method that I wanted to represent. Luckily, I’m not - there is a better way, and it involves the oh-so-magical handleUnknownMessage: withContext: message that every Nu object has.
(Incidentally, this trick requires the most recent revision of Nu from the git repository. Previously the handleUnknownMessage: withContext: message only worked with instances of classes, not class objects themselves - but one line of Objective-C fixed that!)
By declaring handleUnknownMessage: withContext: as a class method on NSFileManager, we can tell the NSFileManager class to forward any messages it can to the shared instance of NSFileManager. Here’s the code that allows one to do that:
(class NSFileManager
(+ (id) handleUnknownMessage:(id)cdr withContext:(id)ctx
((NSFileManager defaultManager) sendMessage: cdr withContext: ctx)))
Beautiful. Now every unknown message sent to NSFileManager will be forwarded to (NSFileManager sharedInstance); this can be implemented with any other singleton class that you please. It’s dynamic behaviors like this that make Nu such a pleasure to work with (and Java so painful - I once wrote an equivalent of Ruby’s method_missing in Java. It was not pretty).
Entry Filed under: functional, magic, nifty, nu, programming. .
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed