Our focus this week shall be on a very simple yet useful design pattern, the Singleton Design Pattern.
So What's The Singleton Design Pattern?
Like a lonely guy, a singleton class has one and only one object instantiated application-wide. The Singleton pattern is categorised as a creational pattern because it provides a very good way of instantiating objects.
This pattern usually involves a single class which takes absolute responsibility of creating it's own object while ensuring no one else does and also ensuring that only one object gets created. A singleton class also provides access to it's only object directly without the need to instantiate an object of the class.
Classes whose purpose is to provide application-wide services are good candidates of the singleton design pattern. To this effect, the singleton pattern is used for components like Loggers, Drivers, Thread Pools, Caches etc.
What Does It Take For A Class To Be A Singleton?
Note that, the whole essence of the singleton design pattern is to ensure that only a single instance of a class exists application-wide and this single object should only be created by the class itself. This means the following conditions should be met:
1. A Private Constructor : The singleton class should have a private constructor to ensure that no object of the class can be created outside of the class itself. Without a public constructor no other code can create an instance of a class. Making the class' constructor private prevents other classes from creating objects of this class. In this case, only the class under discussion can create an object of it's own self.
2. A Private Static Instance : There also need to be a private static instance of the same class that is the only instance of the class. Since an object of the class can never be created outside of the class, we'll need to explicitly instantiate an object of the class under discussion. This single instance should be made static and preferably final as well just so we wouldn't have to instantiate an object of the class (which can't be done anyways) before accessing it.
3. A Public Static Method : This static public method (usually named 'getInstance()') is the global access point for the outer world to get a reference to the single instance of the class under discussion.
I think we've had enough theory to get you confused now! Let's do a hands-on exercise to clear the confusion.
In our hands-on exercise, we'll create a hypothetical database connector class which should help us to execute queries any where within our application. NOTE : We won't actually do any database programming here, we'll only simulate the operations.
In this exercise, we've created a pseudo database connection manager with a public API which is supposed to return a list of all the employees in our database. Assuming this data is so central to our application that we'll want to be able to access it anywhere in our codebase without having to explicitly instantiate objects of our DatabaseManager class, we've made our DatabaseManager class a singleton class.
This means anytime we want to access the list of employees in our database, all we've to do is to call DatabaseManager.getInstance().getAllEmployees();
DatabaseManager.getInstance() will return the only instance of our DatabaseManager class which we'll want to exist application-wide. We then invoke .getAllEmployees() on the instance returned.
Traditionally, we would have written the following lines of codes anytime we wanted to access our employees records.
DatabaseManager dbManager = new DatabaseManager();
The above code does not only demand that we type too much characters, it also wastes system resources because anytime a new DatabaseManager object is created, the database connection driver will have to establish a connection to the underlying DBMS and also perform some house-keeping chores.
Implementing this class as a singleton will ensure that our database connection driver performs it's bootstrapping chores only once. It also ensures that only a single instance of this class exist which helps us to keep a global representation of our class.
Note that we've used a database manager in this example but you can always use the singleton design pattern whenever you want to create a class to provide application wide services.
This is the simplest way to implement a singleton class. We'll take a look at other variants later.
Meanwhile, leave your questions and suggestions using the comments box below and let's learn together.
Let's write clean codes one character at a time!!!