Singletons violate SOLID principles

This is a classic singleton in Java.

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

  private Singleton(){}

  public Singleton getInstance(){
    return instance;
  }

  public void doStuff(){
    //...
  }
}

It is used this way

Singleton instance = Singleton.getInstance();
instance.doStuff();

A singleton violates all five SOLID principles.

  • Single Responsibility: singletons manage their own instantiation besides their own logic (two responsibilities).
  • Open/Close and Liskov Substitution: singletons cannot be extended nor be replaced.
  • Interface Segregation and Dependency Inversion: a singleton can implement an interface, but the interface will be redundant because there will always be a dependency on the concrete class through the factory method.

Example of singleton implementing an interface

public class SingletonImpl implements Singleton{
  //...
  public Singleton getInstance(){
    return instance;
  }
  //...
}

It is possible to use the interface as the type of the instance, but it is inevitable to use the concrete class at least to get the reference.

Singleton instance = SingletonImpl.getInstance();
instance.doStuff();

However, the worst issue is that singletons are not easily testable. With classic singletons, it is necessary to use reflection to mock the instance or the pattern itself must be violated making the instance accessible.