- Audience: you already familiar with Singleton pattern and a couple common implementations in Java.
- Context: this article discusses the Singleton design pattern under the context of Java programming language. It may not apply to other programming languages.
Why Singleton is bad?
- Singleton may not be "single" per application or JVM.
- It requires more work to work with it in unit tests.
- It introduces a global state to the application.
- It makes your code tightly coupled with it. Google: Why tightly coupling is bad?
- It hides the dependencies it depends on, instead of exposing them through the constructor or an interface. A good example: singletons-are-pathological-liars
Singletons are nothing more than global state. Global state makes it so your objects can secretly get hold of things which are not declared in their APIs, and, as a result, Singletons make your APIs into pathological liars.
Single instance per Classloader
Singletons may not be really "single" per JVM or application. Depends on the implementation: e.g. the static variable style implementation - which is accomplished by a static property. In such an implementation, it really means there is one instance per class. In other words, if there are multiple Classloaders, e.g. multiple levels of Classloaders are used in EJB, a Singleton class will not be "single" anymore in an application or JVM.
This article elaborates more examples about how two Singletons can exist simultaneously.
Unit tests are isolated from one another. Having a singleton in unit tests means each unit test may not be independent from the other. Therefore, you need to worry about when to reset its state such that it does not affect other tests, which means more work and maintenance. If you don't reset the global state, it may be hard to debug errors in your tests.
In addition, a singleton usually gets implemented using a static method. Static methods are hard to mock or stub.
What about good
Singletons solve one (and only one) problem:
Resource Contention. If you have some resource that
can only have a single instance, and
you need to manage that single instance,
Compare to a static/utility class, it can have these advantages:
- Polymorphism. Its parameters can be inherited. Allow methods to be overridden by subclasses. Note: it requires the constructor of Singleton to be protected, which probably is not a good implementation for a creation-expensive Singleton.
- If you change your mind and want more than one instance, the Singleton class can be easily altered.
When not to use it?
- The Singleton should not be seen as way to implement global variables.
- If a class has complex dependencies or creation logic that depends on others.
Alternative: Use Dependency Injection instead.
When to use it?
As a rule of thumb, it should only be used to guarantee that one and only one instance of a given class exists during run time. And it hard to achieve by dependency injection.
A few examples:
One logger Singleton for each class.
A couple reasons:
- It's cumbersome to inject a unique logger instance for every class.
- It doesn’t affect the execution of your code.
Immutable Singletons that need polymorphism
Read only singletons storing some global immutable state, which may have subclasses in future.