The more I am exposed to ‘professional developers’ the more I begin to realise that there multiple phases in their Design’s maturity. One of the best way to demonstrate this is to look at how people tend to use the Singleton pattern.
Phases over time
-
Oblivious
- The developer is unaware of Singleton. They don’t use it at all.
- If they come across it in a piece of code they don’t realise it is a common re-occurring piece of code
- Discovery
- The developer comes across an example piece of code, an article or a book that contains singleton and thinks that is really nice.
- They understand how it is used in this context.
- Familiarity
- The developer starts to use Singleton for the first time in one piece of work.
- They develop an understanding of the problem it solves.
- Abuse
- They developer starts seeing the Singleton problem everywhere.
- They create a lot of classes as Singletons
- Maturity
- The developer realises that there are alternatives to the Singleton pattern.
- They start to use Singleton as appropriate.
Now I currently am in a position where I have been through this cycle but I am now starting to see others doing the same thing. I think the important lesson to speed your progress from Abuse to Maturity is the common saying
Do the simplest thing that works.
Isn’t Singleton simple?
Singleton is not the simplest way to ensure that one and only one object is available at all times within the lifetime of a program. That is just a static instance.
static object _instance = new object();
Common usage of Singleton (including the Gang of Four example) combines lifetime availability with lazy instantiation. The issue here is whether lazy instantiation is required. Would it not be simpler to just use a static constructor?
Now I can’t answer that for your project, however what I can tell you is that today I have written my first Singleton in nearly 2 years, because previously all cases where I needed a long lived object that there was only one of, I just used a static instance. Each time these objects were wrapped inside a class, which itself was not static, and only internal members of that class needed access to the long lived object.
So why use a Singleton
Today however I find myself attempting to share a cache between two Dialogs. Both these dialogs use the cache, and both used keyed Indexers (i.e. cache[key]) to get and set the items cached. Unfortunately the definition for an indexer requires an instance variable.
object this[string key] { get { ... } set { ... } }
Now I could have instead dumped the indexer and gone with static methods, but my aim here was not to re-write the underlying cache but just provide a Dictionary<string, Assembly>. So sticking with the Do the simplest thing that works idea, my cache Is-a Dictionary<>, this means that I don’t have to re-write all of the methods that I want to expose. In fact I expose much functionality than I currently use. This meant that all I had to write was the singleton instance.
/// <remarks> /// Would just be a Dictionary<String, Assembly> but
/// I want to keep only a single static copy /// </remarks> class ChooserCache : Dictionary<string, Assembly> { private static Dictionary<string, Assembly> _cached
= new Dictionary<string,Assembly>(); private ChooserCache() { } public static ChooserCache Instance { get { return _cached; } } }
The alternative was to go the Has-a route and implement each and every method as a static which referred to a static instance of the Dictionary. This also means that I have to add new methods as I use more functionality from the Dictionary itself.