Singleton Pattern   «Prev  Next»
Lesson 1

Singleton Design Pattern

The first design pattern examined in this course is the Singleton Design Pattern. The Singleton Design Pattern is used when there should only be one instance of a given class. It uses static, class methods and private constructors[1] to strictly control creation of new instances of the class.
In this module, you will learn:
  1. The ten elements that distinguish a pattern
  2. The intent of the Singleton pattern
  3. When to use the Singleton pattern
  4. The structure of the Singleton pattern
  5. How the Singleton pattern is used in the real world

The Singleton Class Explained

In the domain of software design, the Singleton class holds a distinctive position. Based on the provided definition, a Singleton class is one that embodies the principle of exclusivity in object instantiation. This exclusivity ensures that only one instance, or object, of this class is created throughout the entire runtime of a software application. This singular object serves a crucial purpose. By its very nature of being the sole instance, it becomes a global resource, accessible to all clients or components within the system. Such a global facility ensures a centralized point of access, guaranteeing consistency and coherence in operations that rely on this specific object. The Singleton pattern, from which this class derives its name, is thus primarily employed to maintain this controlled access and ensure that no duplicate or parallel instances emerge, which could otherwise lead to discrepancies or conflicts within the system. In essence, the Singleton class epitomizes a design approach where exclusivity and centralized access are paramount, ensuring that the entire system benefits from a consistent and unified resource.
For that reason, computer-generated random numbers should really be called pseudo-random numbers. In most algorithms for generating a sequence of pseudo-random numbers, you start with a seed value and transform it to obtain the first value of the sequence. Then you apply the transformation again for the next value, and so on.

The Java library uses a linear congruential generator and the seed is transformed according to the equation
seed = (seed * 25214903917 + 11) % 248

Typically, the seed of a random number generator is set to the time at its construction, to some value obtained by measuring the time between user keystrokes, or even to the input from a hardware device that generates random noise. However, for debugging purposes, it is often helpful to set the seed to a known quantity. Then the same program can be run multiple times with the same seed and thus with the same sequence of pseudo-random numbers. For this debugging strategy to be effective, it is important that there is one global random number generator. Let us design a class SingleRandom that provides a single random number generator. The key to ensuring that the class has a single instance is to make the constructor private. The class constructs the instance and returns it in the static getInstance method.
public class SingleRandom{
 private SingleRandom() { generator = new Random(); }
 public void setSeed(int seed) { generator.setSeed(seed); }
 public int nextInt() { return generator.nextInt(); }
 public static SingleRandom getInstance() { return instance; }
 private Random generator;
 private static SingleRandom instance = new SingleRandom();

Note that the static field instance stores a reference to the unique SingleRandom object. Recall that a static field is merely a global variable and in Java, every field must be declared in some class. We find it convenient to place the instance field inside the SingleRandom class itself.

Dangers of using a Global Variable

The global variable is one of the old programming practices that creates side effects for the object-oriented programmer. Global variables tie classes into their context, undermining encapsulation. A class that relies on global variables becomes impossible to pull out of one application and use in another, without first ensuring that the new application itself defines the same global variables. Although this is undesirable, the unprotected nature of global variables can be a greater problem. Once you start relying on global variables, it is perhaps just a matter of time before one of your libraries declares a global that clashes with another declared elsewhere. By using globals, though, you potentially leave your users exposed to new and interesting conflicts when they attempt to deploy your library alongside others. Globals remain a temptation, however. This is because there are times when the inherent negative side effects of using global access seems a price worth paying in order to give all your classes access to an object. Namespaces provide some protection from this. You can at least scope variables to a package, which means that third-party libraries are less likely to clash with your own system. Even so, the risk of collision exists within the namespace itself.

[1]constructor: A pseudo-method that creates an object.

SEMrush Software