Singleton

Intent

  • Ensure a class only has one instance, and provide a global point of access to it

  • Encapsulate lazy instantiation[1]

1. aka just-in-time initialization or initialization on first use

Motivation

  • It is important for some classes to have exactly one instance:

    • a printer spooler

    • a file system

    • an window manager

    • a data converter

  • How do we ensure that a class has only one instance and that the instance is easily accessible?

    • A global variable makes an object accessible, but it doesn’t keep you from instantiating multiple objects.

  • A better solution is to make the class itself responsible for keeping track of its sole instance.

Applicability

Use the Singleton pattern when:
  • there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point

  • when the sole instance should b extensible by subclass and clients should be able to use an extended instance without modifying their code

Structure

Diagram

Consequences

Benefits
  1. Controlled access to sole instance.

  2. Reduced name space.

  3. Permits refinement of operations and representation.

  4. Permits a variable number of instances.

  5. More flexible than class-level operations.

Drawbacks
  1. Violates Single Responsibility Principle

  2. May mask bad design (components know too much about each other)

  3. In multithreaded contexts, a singleton may be created several times

  4. Decreases the controllability of the client classes, which becomes harder to test

Implementation Tradeoffs

  • Lazy initialization can be used to ensure that the class is only instantiated when needed

  • Some languages already support singletons: Scala, Groovy, Ruby…​

Singletons in Scala

object Logger:
  def info(message: String): Unit = println(s"INFO: $message")

Singletons in Groovy

// Use @Singleton to create a valid singleton class.
// We can also use @Singleton(lazy=true) for a lazy loading
// singleton class.
@Singleton
class Util {
    int count(text) {
        text.size()
    }
}

assert 6 == Util.instance.count("mrhaki")

Singletons in Ruby

require 'singleton'

class Config
  include Singleton

  def foo
    puts 'foo'
  end
end

config = Config.instance
config.foo

Author and Date

  • Design Patterns: Elements of Reusable Object-Oriented Software. Erich Gamma, Richard Helm,Ralph Johnson, and John Vlissides. Addison Wesley. October 1994.

More Examples

Simple Singleton in Java

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Singleton with holder class in Java

public class Singleton {

    private Singleton() {
    }

    public static Singleton getInstance() {
        return Holder.instance;
    }

    private static class Holder {
        public static final Singleton instance = new Singleton();
    }
}

Singleton