Design pattern - The Singleton

> Code - (Programming|Computer) Language > Design Pattern

1 - About

The singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.

Singletons usually are used to provide a single point of access to a global service. It doesn't have to instantiate the object. It just has to provide access to the object. The object returned can be set by any means necessary.

Advertising

3 - Example

3.1 - Database

Application uses database connection pooling, so one DB connection can be shared among many requests. The singleton is usually the object which manages this pool.

4 - Instantiation

A singleton with parameters is NOT a singleton because you may have more object than one of them.

If you want your singleton to be initialized with some data, you may pass them after initialization (or via a builder pattern)

SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data

5 - Anti-Pattern

Singletons are an anti-pattern. They have private constructor and they are then very hard to subclass and configure.

6 - Implementation Type

6.1 - Static (Language-specific)

You can implement singletons by using language-specific features, such as the static keyword for Java

6.2 - Object

A singleton allows access to a single created instance that can be:

  • passed as a parameter to other methods,
  • treated as a normal object.
  • and therefore can implement interface
Advertising

7 - Object Implementation

From the less desirable to the most desirable solution.

7.1 - Method Initialization

public class MethodInitializationSingleton {
 
    private static MethodInitializationSingleton singleton;
 
    private MethodInitializationSingleton() {
    }
 
    public static MethodInitializationSingleton getSingleton() {
        if (singleton == null) {
            singleton = new MethodInitializationSingleton();
        }
 
        return singleton;
    }
 
}

This implementation is not Thread-safe. If two threads, Thread 1 and Thread 2, call getInstance() at the same time, two instances can be created.

If Thread 1 is pre-empted just after it enters the if block and control is subsequently given to Thread 2.

7.2 - Class initialization

Class initialization (ie Eager initialization) with a static initialization block in order to manage exception.

public class ClassInitializationSingleton {
 
    private static final ClassInitializationSingleton singleton;
 
    static {
        try {
            singleton = new ClassInitializationSingleton();
        } catch (Exception e) {
            throw new RuntimeException("An error occurred!", e);
        }
    }
 
    private ClassInitializationSingleton() {
    }
 
    public static ClassInitializationSingleton getSingleton() {
        return singleton;
    }
 
}
  • Class initialization is thread-safe because of the Java specification.
  • It is possible to instantiate more than one Singleton instance using Java reflections (by modifying the constructor to Accessible and calling it)

7.3 - Synchronized Method Initialization

public class SynchronizedSingleton {
 
    private static SynchronizedSingleton singleton;
 
    private SynchronizedSingleton() {
    }
 
    public static synchronized SynchronizedSingleton getSingleton() {
        if (singleton == null) {
            singleton = new SynchronizedSingleton();
        }
 
        return singleton;
    }
 
}
  • Synchronized methods are quite costly.
  • It is possible to instantiate more than one Singleton instance using Java reflections (by modifying the constructor to Accessible and calling it)
Advertising

7.4 - Enumeration

In Java, Enumerations can contain method implementations and hence can be used to implement Singleton’s logic.

See Enum Singleton

8 - Java

9 - Documentation / Reference