Monday, May 28, 2007

Singleton: Ammendment 2

I've found an intersting question regarding the Singleton pattern that might be worth examining: "What if the class that is supposed to become a Singleton doesn't have parameter less constructor?"
(If you need to read explanations on the pattern read here and here)
Hmmm! No why would you have a singleton where its constructor accepts parameters? It kind of sounds useless since no one is supposed to create instances of the singleton class.
But just for the sake of argument lets assume we have a singleton class with such properties: for example we've decided to create a log helper as a singleton. It's a class that's going to be used all over our program and anyone who needs to log something will send it to this class. The log helper would take care of writing the entry to all the different log output devices. Again for argument's sake let's assume that we have created the constructor of this class so that it accepts some settings in regards to how it's supposed to behave (don't ask why!):


class LogHelper
{
/* Logging method implementations */

private LogHelper(some-configuration-value)
{
//use the some-configuration-value or store it somewhere
}

public static LogHelper Instance
{
get
{
return _instance;
}
}
private static LogHelper _instance = new LogHelper(/*how to provide the param?*/);
}


As you can see the big question is how do we provide the parameters to the constructor. Well the issue here is a little bit of a bad design: WHY would you want to pass something to the constructor of the class your designing when no one can actually call the constructor but yourself? Weren't you better off just extracting the parameters or config values or what ever it was supposed to be passed to the constructor in the constructor itself? That would be a better implementation.

Now the above example is very simple (and stupid) but there are situations where a constructor with parameters could help a Singleton design! Surprised? Well here is a situation:
Suppose we were building a class called PrintManager, this class is going to manage the queue of documents that are waiting to be printed to a specific printer and it is also going to handle the printing operations (don't really care about that part). The only thing important about this design is that the PrintManager is going to be a multi-instance singleton meaning that multiple instances will be available, each instance managing a specific printer. Now for simplicities sake we are going to assume that all the printers are the same (one class can handle them all) but each printer is on a different port so when we create the printer object we need to tell it (via the constructor) on what port to print to.
Even in this case the code responsible for creating the PrintManager object is still part of that class so if the PrintManager object has no parameters in the constructor or has 10 parameters it doesn't really affect anyone and it's an internal thing. See the code below:


class PrintManager
{
private int Port;
/* printing & queue management code */

private PrintManager(int p)
{
Port = p;
}

public static PrintManager GetInstance(int forPort)
{
lock(Instances)
{
if (Instances.ContainsKey(forPort) == false)
Instances.Add(forPort, new PrintManager(forPort));
}

return Instances[forPort];
}
private Dictionary Instances = new Dictionary();
}


As can be seen in the above code the internal code of the PrintManager class has to deal with the constructor so again having parameters or not having them doesn't really matter.

No comments: