Michael Safyan

Singleton

Singleton Anti-Pattern

Overview

In the Singleton pattern, there is an object for which there is an assumption that there will only ever be one instance of that object. While one can simply construct a single instance of the object and no other instances, doing so is not the Singleton pattern. The Singleton pattern emerges when the singleton-ness of the object is baked into its definition, typically by providing a function to retrieve the sole instance and making the constructor accessible to only this function.

The name of the function that retrieves the sole instance is typically called "getInstance()", "instance()", or "get()", although the name used is not important to make the object a singleton. It is also not necessary for the object to be constructible at all; any use of global (or "static") variables for maintaining state is also a type of singleton.

Why not to use

Bad, Brittle Assumption

The biggest problem with the singleton pattern (and why it is, therefore, a design anti-pattern rather than a design pattern) is that the assumption that there will ever be only one instance is often broken during a project's lifetime, and this pattern structures the code in a way that requires a very significant effort to refactor when this assumption is inevitably wrong. For example, we might reasonably assume that there will only be one HTTP request processed by our application at a time under the assumption that a new instance of the process is instantiated for every incoming HTTP request that must be processed. Thus we might initially write the HTTP request object as a singleton. However, if we were to later modify the architecture to use multiple threads to handle many requests within a single instance of the application, this assumption suddenly turns out to be false, and it becomes necessary to rework the code significantly to handle this new condition. Another example may be the object representing a particular library that we happen to use in the application. We might reasonably assume that there will only ever be one case of that library, but then turn out to be wrong when we dynamically load the library and need to be able to reference multiple versions of the library in order to gracefully transition from one version of the library to another during the process of updating the library without needing to completely restart the application. This and numerous other examples demonstrate the need to ensure that the code is flexible in the event that the assumption of singleton-ness turns out to be false, and this pattern makes the code inflexible.

Difficulty Testing

In addition to making the code inflexible, the singleton pattern also makes it very difficult to test code. This is because the singleton pattern introduces a dependency through a side-channel that is not explicitly given as a parameter to constructors or other functions that use it. Even in the event that this side channel can be replaced (and often doing this is very difficult), the need to do so is less obvious and makes tests very difficult to understand.

Thread-safety Bugs

Even ignoring the issues above (which are, I believe, the strongest reasons to avoid this pattern), the singleton pattern is especially difficult to implement correctly when taking multithreading into account (though this is more a case to use a library to implement the pattern when using the pattern rather than a case to avoid it). On that note, though, the singleton assumption does require that the singleton object, itself, be thread-safe; however, moving the singleton property outside of the object allows one to create alternative implementations, some of which are thread-safe and others which are not, which then allows applications that are not multithreaded to instantiate a version of the object that doesn't have the overhead of thread synchronization while allowing multithreaded applications to instantiate the thread-safe version.

General pattern

Java

      public class NameOfSingletonObject {
        // ...

        // Returns the sole instance of this object. The object can either
        // be lazily created on the first invocation (a "lazy singleton") or
        // it could have been created earlier when the class was initialized
        // such as by using static field initialization (an "eager singleton").
        public static NameOfSingletonObject getInstance() {
          // ...
        }

        // A defining feature of the singleton pattern is that the
        // object cannot be constructed directly and instead is retrieved
        // through some other function that returns the instance
        private NameOfSingletonObject(/* ... */) {
          // ...
        }

        // ...
      }
    

C++

      class NameOfSingletonObject {
       public:
        // ...

        // Returns the sole instance of this object. The object can either
        // be lazily created on the first invocation (a "lazy singleton") or
        // it could have been created earlier when the class was initialized
        // such as by using static field initialization (an "eager singleton").
        static NameOfSingletonObject* Get();

        // ...

       private:
        // A defining feature of the singleton pattern is that the
        // object cannot be constructed directly and instead is retrieved
        // through some other function that returns the instance
        NameOfSingletonObject(/* ... */);

        // ...
      };
    
What to use instead

Instead of using this pattern, simply instantiate a single instance and propagate it to places that use the object as a parameter to make the dependency explicit. For example, instead of this:

     // BAD: Using singleton
     public class CloseButtonHandler implements ButtonHandler {
        @Override
        public void buttonPressed() {
          // What will we do if we ever redesign the app to have multiple windows?
          // Using a singleton like this is inherently fragile.
          Window.getInstance().closeWindow();
        }
     }
  

... you should do this, instead:

     // GOOD: Allows dependency to be supplied explicitly
     public class CloseButtonHandler implements ButtonHandler {
        private final Window window;

        public CloseButtonHandler(Window window) {
          this.window = Preconditions.checkNotNull(window);
        }

        @Override
        public void buttonPressed() {
          window.closeWindow();
        }
     }
  

Both of the examples will work, but in the second example, the singleton object needs to be provided explicitly (the fact that it is singleton is merely a property of the application / caller, not of the object, itself), which then allows tests to supply an alternative implementation and makes the code capable of dealing with multiple instances in the future.

It should be noted that a common objection to structuring code as in the second version is that doing so may result in a large number of parameters in code that relies on many singleton objects. This problem, however, is often exacerbated by passing indirect dependencies and can be fixed by passing direct dependencies or by encapsulating multiple dependencies together into a single object; for example, instead of passing four dependencies that are not used directly and are only used to instantiate some fifth object, pass a factory object that creates this fifth object and encapsulates these four dependencies, instead, so that you only need a single dependency. In addition, the burden of having to pass multiple explicit dependencies can also be greatly reduced by using a dependency injection framework such as Dagger.

Real Examples

Although Singleton should generally be avoided, it is nevertheless an extremely common and popular pattern. If you're curious to see how this pattern is used in the wild, you may find these real examples from GitHub to be helpful:

Further Reading
Disclaimer

My statements are my own and do not necessarily reflect the opinions of Google Inc.