Lesson 6 | Singleton: participants and collaborations |
Objective | Classes comprise a Singleton and Clients interface with Singleton. |
Classes comprise a Singleton and Clients interface with Singleton
Let me set the stage to explain how clients interface with a Singleton class within the context of design patterns.
Picture this: a vast expanse of software architecture where numerous objects and classes live and interact. In the midst of this bustling cityscape, one skyscraper stands alone - the Singleton. The Singleton class, unique and solitary, houses one instance that is universally accessible. It is the keeper of a valuable resource that is needed across the system, a resource that only it can provide. A perfect example might be a log file writer that the whole system uses to log application events. It's paramount that only one instance manages this task to avoid conflicting entries or overwriting.
Now, imagine client classes as the residents of this digital city. They have needs that only the Singleton can fulfill. But how do they reach out to the Singleton?
The interaction between clients and the Singleton is a study in restriction and access. The Singleton is like an exclusive club with a fiercely guarded entrance: the private constructor. This private constructor prevents the creation of new instances of the Singleton. However, the Singleton has a gatekeeper, a public method, often named getInstance(). This is the only door through which client classes can access the Singleton.
To make a request, a client invokes the getInstance() method. This method checks if an instance of the Singleton already exists. If it does, the Singleton responds with a reference to that single, unique instance. If not, the Singleton creates it and then returns it. This way, the Singleton class ensures that only one instance of itself ever exists, and that instance can be accessed globally from within the application.
One critical element of this narrative is that the Singleton needs to ensure thread safety, which is like crowd control at a popular event. Let's say several clients try to access the Singleton simultaneously. Without proper control, this could lead to multiple instances being created, breaking the Singleton pattern. To avoid this, the Singleton employs mechanisms such as synchronized blocks or "Double-Checked Locking", to ensure that only one thread at a time can access the creation process. It's the digital equivalent of allowing one person at a time through a turnstile.
So, in the grand drama of software design patterns, the Singleton takes center stage as a pivotal character. It offers a unique service that all other objects can access but regulates this access to ensure that it can maintain the control and integrity of its solitary instance. It's a fascinating and critical role that shapes the story of many software systems. However, it is essential to remember that it must be used wisely to avoid misuse or over-complicating the system.
The Singleton is a particularly simple pattern because it only has one class and two responsibilities. Thus, its participant list looks like this:
- Singleton
- Create the unique instance
- Provide a reference or pointer to that instance
Most patterns have much larger participant lists.
Collaborations
Singleton is such a simple pattern that it really does not say much about collaborations. Its collaborations list looks like this:
- Clients use the
getInstance()
method to get a pointer or reference to the unique instance of the Singleton.
A client is any object or class outside the pattern; generally one that only knows about the public interface that the pattern and its classes present,
rather than about its private implementation.
Singleton With No Subclassing
- First, let us look at the case where we are not concerned with subclassing the Singleton class
- We will use a static method to allow clients to get a reference to the single instance
Class Singleton is an implementation of a class that only allows one instantiation. There is private reference to the one and only instance. The Singleton returns a reference to the single instance and creates the instance if it does not yet exist. This is called lazy instantiation.
The Singleton Constructor is private and the client can instantiate a Singleton object
public class Singleton {
private static Singleton uniqueInstance = null;
private int data = 0; An instance attribute.
public static Singleton instance() {
if(uniqueInstance == null)
uniqueInstance = new Singleton();
return uniqueInstance;
}
private Singleton() {}
// Accessors and mutators here
}
Here's a test program:
public class TestSingleton {
public static void main(String args[]){
// Get a reference to the single instance of Singleton.
Singleton s = Singleton.instance();
// Set the data value.
s.setData(34);
System.out.println("First reference: " + s);
System.out.println("Singleton data value is: " + s.getData());
// Get another reference to the Singleton.
// Is it the same object?
s = null;
s = Singleton.instance();
System.out.println("\nSecond reference: " + s);
System.out.println("Singleton data value is: " +
s.getData());
}
}
And the test program output:
First reference: Singleton@1cc810
Singleton data value is: 34
Second reference: Singleton@1cc810
Singleton data value is: 34