Static Class Vs Singleton Class – What to use when
There is sometimes a debate about whether to use a pure Static Class or a Singleton Class. The obvious question here would be – Why are we even comparing a Static Class with a Singleton Class in
the first place? Well that’s a fair question.
Let’s first define a Singleton Class. A Singleton class is a class which can have at the most one instance.
A Static Class, on the other hand, contains only static methods and attributes and therefore does not require instantiation.
One could argue that in most cases, if not all, a static class can imitate the behavior of a Singleton class fairly well. Also, defining and consuming a Static Class is simpler than implementing a Singleton class. But, an overly simplified approach may not always be an apt option.
It seems that in quite a few cases either of the two can be used. This creates confusion in our minds about which one to use. This blog is intended to unravel the mystery that has been looming in some our minds for some time now.
Two sides of the same Coin or not
In an Object oriented world, a Class is more like a template or a definition for an entity. Objects are the result of instantiating a Class which represent entities. For example, Student is class where you define the attributes and operations whereas Mike, Smith or Jane is objects of Student class which are a result of instantiating the Student class. They will off course behave as defined in the Student class.
A Singleton Class is a design pattern first formulated by Gang of Four. A property of Singleton class which diversifies it from a regular class is that the implementation of Singleton class ensures that it can be only instantiated once. One example of a Singleton class is a Logger class which can be globally consumed within multiple sub-systems for logging information and warning messages occurring during an end-to-end process. As an application developer you don’t want to instantiate more than one instances of Logger class because then either each sub-system will have their own loggers or they will not have the correct instance of logger class to feed the messages.
Most, if not all, of the Object Oriented programming languages would support static attributes and methods in a Class. As mentioned earlier, classes are the skeleton which defines how the objects will behave once instantiated. An attribute or method is defined as static if it is to be shared amongst all the instances of a class. So, a static attribute will hold the same information across all the instances of the class compared to an instance attribute where each instance will hold its own value. Consider an example of Webpage which wants to count the no. of hits to the page on Internet will model a static attribute to hold the no. of visits. Similarly, methods or functions can be modeled as static which contains one source of truth for all the instances of a class. For obvious reasons, a static method will only be able to access the static parts of the class.
Mostly we get thrilled and find it convenient to create pure static classes altogether. One such example is a Database Layer class representation where we implement all the open SQL queries. The Business Logic Layer class can call static methods on this DB layer class for any SQL queries that it want to execute on the Database. This way we also segregate the responsibilities and areas of concern.
By the way, a pure static class would be wherein all the attributes and methods are static and there is no scope of instantiation.
There is little to choose between the two, Singleton and Static class. Singleton implementation will always restrict the no. of its instances to one, provided it is implemented correctly. And a static class will not have an instance at all but, will be able to implement the same functionality as Singleton using Static methods and attributes.
Unraveling the Mystery
I hope explanation in the previous sections is clear as to why we are comparing Singleton with Static classes. Now, let us finally look at what are the challenges when taking the simpler approach of implementing a Static class in lieu of Singleton.
1. Polymorphism is a very compelling concept of Object Oriented programming. Polymorphism allows you define an interface and implement that in many ways. And at runtime you can determine, which implementation should be called. This can be achieved with Inheritance, another very significant concept in OOPS. With all the methods and attributes of a class defined as static it cannot be sub-classed. If I have decided to implement a pure Static Class then, I must be very sure that I will never have to subclass it. Law of Nature is also that the requirements are never completely stated which implies that changes are inevitable. A static class can never reap the benefits that Polymorphism has given to this World. It may be worthwhile to keep the option open to allow polymorphism for future even if it is not required to start with.
2. Initializing a Static Class pose another challenge as compared to a Singleton Class. For a Static Class it would not make much of sense to implement an instance Constructor. As discussed before, an instance of a Static class will have no members which are instance specific and misleading to create instances of such a class. Even if, we were to create instances of a Static Class then also, its instance Constructor would initialize the same shared static members over and over again possibly producing incorrect results. The only relevant placeholder for initializing such a class would be a Class Constructor or a Static Constructor. One disadvantage in a Class Constructor is that it does not have exporting or importing parameters and it does not allow to propagating exceptions.
3. Finally, object oriented programming is based on the concept of explicitly instantiating objects of a class but, in case of pure static classes there is no instantiation of the class. The static classes are loaded by the compiler when the class is first encountered in the code by calling its implicit or explicit Class Constructor. A disadvantage from memory consumption perspective is that there is no way to explicitly free up the memory space occupied by static classes. The class stays in the memory till the internal session exists. In short, we can neither control when the static class should be initialize nor we can free up the memory taken my static class when we want to.
It would be interesting to revisit the Logger example to understand if there is any real advantage of using it as a Singleton instead of a Static Class.
Initially the requirement was to have a Logger class which will hold information, warning and error messages for the entire application during a session and displays to the user. The messages will span across all the sub-systems and share the same Logger Class.
Let us create a Singleton Class to map the Logger utility.
It is important to define the Instantiation as ‘Private’ for a Singleton class as a first step to ensure that CREATE OBJECT cannot be called from outside the Logger class.
Also, it is good programing practice to make the Singleton Class as ‘Final’. If the class is not declared Final then it is allowed for inheritance. It will be a bad design to allow sub classing for a Singleton class. Moreover, Singleton property of the Superclass is not automatically inherited by Subclass so we end up allowing multiple instantiation of the Subclass.
Define a private class attribute to hold the reference of this Logger class.
Now, create a Class method to streamline the instance creation process which controls that the Logger class can be instantiated only once. Remember, it is imperative that we have only one instance of the Logger to collect all the messages for the Application.
Implement the GET_INSTANCE method to enforce Singleton behavior.
Now, add Logger specific functionality to this Singleton Class.
All went fine till the requirements changed one fine day. As per the new requirement, we need to have separate Logs created for each of sub-systems. Messages from some sub-system had to be displayed to the user and for few they had to be written to a file.
Based, on the above requirement, I am required to remove the singleton constraint from my existing Logger class and allow public instantiation. This is to allow creation of one Logger instance per sub-system which allows segregating and de-coupling behavior of message output. One option is also to use inheritance to subclass Logger class for messages to be written to a file. In future, if the requirement changes again and there are new target for capturing messages from a sub-system, I would merely need to extend the Logger class and implement the specific behavior.
Had we chosen to use a pure Static Class to implement the Logger in the first place, it would have been difficult to manage the ever changing requirements. We would have ended-up adding many static methods in the same class which are performing disjoint operations failing the Single Responsibility principle. Achieving the requirement of multiple Log handlers, one for each sub-system, would perhaps have made the code hard to maintain and extend.
Implementing a pure static class is not an Objected Oriented way of solving a problem and hence, does not allow to fully exploiting the capabilities of Object Oriented design principles. On the other hand, implementing a Singleton class may be a touch complex than Static Class but, it allows keeping your design open for enhancements and closed for modifications which are an important OO Design Principle.
It is still alright to solve a very trivial problem through Static Class but, the moment we realize that non-trivial requirements are creeping through; it is time to go for a Singleton.