Software Design Patterns: Singleton in a Nutshell

Javier Gonzalez
Javarevisited
5 min readDec 30, 2020

--

Creational design patterns provide options for object creation (instantiation of a class ) because sometimes, the basic form of object creation could result in design problems or in added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. They are composed of two dominant ideas: the first one is encapsulating knowledge about which concrete classes the system uses; and the second one is hiding how instances of these concrete classes are created and combined. The Singleton Pattern is one of the most used design patterns. It is an example of the second dominant idea: it hides how instances of a concrete classes are created.

Goal

The goal of a Singleton is to ensure that there is one and only one instance (object) of a class. It is used to provide a global point of access to the object. For instance, logging, data source access, thread pools, configuration settings management, connection instances, and so on. Singleton is sometimes combined with the Factory pattern to guaranty that only one Factory will exist in the whole system.

Solution

How can we ensure that only one instance can exist? Well, we can do that in three steps. Let’s review them.

Imagine that you have a class DataSource which implements the gathering of data from a hardware device connected to your computer or from a remote server. Our DataSource class could be as shown in Figure 1. Nothing special there, just a class like any other — a class with attributes and methods.

Figure 1. DataSource.java — a simple class

You do not want multiple DataSource objects where each object will create its own connection and therefore multiple objects competing for access. Let us transform it into a Singleton DataSource.

Step 1. A Private Constructor

First, in order to create an instance of our class, other classes will call the constructor, right? Something like this:

DataSource ds = new DataSource();

Constructors are public because usually, we want other classes to call them. The first step to create a Singleton is to change the access modifier from public to private (or protected). Why? To avoid any class from creating instances. Nobody will be able to create instances of a class if you make the constructor private. So, are we moving from being able to create N objects to be able to create created 0 objects? Yes, that is the point so far.

Step 2. A Static Public Method

We need a method that replaces the constructor, a public method that other classes can use to ask for an instance. Particularly, we need a method that can be called without creating an object of the class (since at this point we cannot create an object, we just make the constructor inaccessible). We need a static method. Such method is called getInstance() in the Singleton Pattern template and developers usually keep that name.

The method getInstance() will give us a new object from the class, just as a constructor would. The method getInstance() should be public (every other class should be able to access it), should be static (as described before), and should return an instance of the class (in our example, return a DataSource). The method looks as follows:

public static DataSource getInstance() {}

Now, the body for the method. There are two scenarios when a DataSource instance is requested:

  • if it is the first time, then create a new object; otherwise,
  • just return the reference of the object created when the first call occurs. This seems to be pretty straightforward to implement.
public static DataSource getInstance() {
if (instance == null)
instance = new DataSource ();
return instance;
}

Wait, what is that instance variable there? Well, we need a variable to know if we already create an object or not.

Step 3. A Static Instance

The instance variable needs to be static since we need to access it inside of a static method. Notice that we are calling the constructor inside of the method getInstance(). The constructor cannot be called from the outside, but the class can use it.

Our new DataSource class applying the Singleton Pattern is as shown in Figure 2. Notice:

  • the static variable in Line 2;
  • the public static method getInstance() in Line 6; and,
  • the private constructor in Line 12.
Figure 2. DataSource.java — implementing the Singleton Pattern

Having this, in any place in which access to the DataSource is needed, we can use the instruction DataSource.getInstance(). We can store the instance in a local variable or we can directly call methods as needed. For example:

DataSource ds = DataSource.getInstance();
ds.send("Hello");

or

DataSource.getInstance().send("Hello");

Class Diagram

Singleton is one of the few design patterns that does not use interfaces (or a set of classes) involved. Further, there is an element named Singleton involved. The class name should be as needed in the context of the problem being solved, such as in our example DataSource.

Figure 3. Class diagram for our DataSource class applying the Singleton Pattern: private constructor, getInstance() method, and static instance of the same class

Figure 3 shows the Singleton template (as a class diagram):

  • private or protected constructor,
  • static attribute commonly called instance, and
  • the public static getInstance() method.

Very simple but powerful. However, there are no golden hammers. Be careful to not abuse this tool. You do not want to end with a procedural solution in an object-oriented language.

Sample Applications

Are there examples of the Singleton pattern been used in some framework or library? Yes. Let us review some.

java.util.logging.Logger

Logging is the process of writing log messages during the execution of a program to a central place. Logging allows you to record error, warning, and info messages. The Logger object provides logging capabilities. For example:

import java.util.logging.Logger; 
public class Example {
public static void main(String[] args) {
// Create a Logger with class name Example
Logger logger = Logger.getLogger(Example.class.getName());
// Call info method
logger.info("Hello!");
logger.log(Level.WARNING, "Bye");
}
}

Logger is a Singleton and the method getLogger() provides access to the Logger instance.

java.awt.Desktop

The Desktop class provides access to the host’s default browser, email client, and printer, among other things. The Desktop can be accessed as shown in the example below:

import java.awt.Desktop; 
public class Example {
public static void main(String[] args) {
try {
URI uri = new URI("mscjaviergs.medium.com");
Desktop d = Desktop.getDesktop();
d.browse(uri);
}. catch (Exception e) {
}
}
}

Desktop is a Singleton and the method getDesktop() provide access to the Desktop instance.

Notice that getInstance() is the name in the pattern template, but you can customize it, such as getDesktop() and getLogger().

Now you have the big picture. Hope you enjoy reading. Feel free to leave your comments or questions below.

--

--

Javier Gonzalez
Javarevisited

Assistant Professor @ California State | Former Software Engineer | ACM Distinguished Speaker | Research: Intelligent Systems, HCI, Emotion AI, CS Education.