Often times there is a need to share a single object of a class throughout the code base. For example, we might want to store all online users in one central registry or share a central queue amongst all producer and consumer objects. We want to:
- ensure that exactly one object of a class exists.
- provide a way to get that object.
This is a valid and a very common requirement but is often equated and related to a design pattern called Singleton. While they provide a quick and easy solution, singletons are considered bad because they make unit testing and debugging difficult. Brian Button has made some valid arguments against singletons:
[Singletons] provide a well-known point of access to some service in your application so that you don’t have to pass around a reference to that service. How is that different from a global variable? (remember, globals are bad, right???) What ends up happening is that the dependencies in your design are hidden inside the code, and not visible by examining the interfaces of your classes and methods. You have to inspect the code to understand exactly what other objects your class uses.
One of the underlying properties that makes code testable is that it is loosely coupled to its surroundings. This property allows you to substitute alternate implementations for collaborators during testing to achieve specific testing goals (think mock objects). Singletons tightly couple you to the exact type of the singleton object, removing the opportunity to use polymorphism to substitute an alternative.
He’s absolutely right. It’s very difficult to write unit tests for code that uses singletons because it is generally tightly coupled with the singleton instance, which makes it hard to control the creation of singleton or mock it.
Recently I came across a project that made very liberal use of singletons. When I asked the developer about it, he said: “I know singletons are bad. But I needed a single instance of objects in all these cases and had no choice but to use the singleton.” Wrong. Having a single instance is a valid requirement, but singletons are not the only solution. A cleaner alternative would be to create objects in one place like the main()
method and pass them to other classes that need them using their constructors. This concept is called ‘Dependency Injection’.
To illustrate these concepts, let’s look at few example. Suppose we want to store all online users in a central registry and provide a way to find out whether a user is online or not by the username. If we use singletons, the code would look like:
public class SomeClassUsingSingleton {
public boolean isUserOnline(String username) {
// Obtain singleton instance directly
UserRegistry userRegistry = UserRegistry.getInstance();
return userRegistry.get(username) != null ? true : false;
}
}
Let’s rewrite the above code to use dependency injection instead of singletons. In this example, UserRegistry
object is created in the main()
method and passed to the class via its constructor:
public class SomeClassUsingDependencyInjection {
private final UserRegistry userRegistry;
// Creators of the class pass an instance of UserRegistry
public SomeClass(UserRegistry userRegistry) {
this.userRegistry = userRegistry;
}
public boolean isUserOnline(String username) {
return userRegistry.get(username) != null ? true : false;
}
}
Problem solved. However initializing all objects in the main()
method and passing them where they are needed is a mechanical task and increases the number of arguments that declared in constructors. Dependency injection (DI) frameworks and containers like Google’s Guice or Spring are designed to automate this task. You just declare dependencies on objects where you need them and the framework automatically provides or injects them. It’s that simple. Let’s rewrite the above example using Spring:
public class SomeClassUsingSpringDI {
@Autowire //Will be injected automatically by Spring
private final UserRegistry userRegistry;
public SomeClass() {
}
public boolean isUserOnline(String username) {
return userRegistry.get(username) != null ? true : false;
}
}
And the UserRegistry
class is declared as a Spring component:
@Component
public class UserRegistry {
...
}
We can also have multiple implementations of the UserRegistry
such as one that uses an in-memory data structure to store users and another one that uses an external cache, and tell the DI framework to pick and inject the right one at run-time.
To write testable code, we must separate object creation from the business logic and singletons, by their nature, prevent this by providing a global and a static
way of creating and obtaining an instance of their classes. They make it impossible to mock and isolate methods that depend on them for testing. The new
operator is no different and same arguments apply. Dependency injection frameworks centralize object creation and separates it from the business logic making it possible to isolate methods and write good unit tests. Projects of all sizes can benefit from DI frameworks. I normally include a DI framework form the very start because it’s tough to resist the singleton temptation half-way through the project when you really need it and don’t have time to mess around setting up DI.
Comments (4)
Frank
Singletons represents global state and should be used sparingly. We use them to store configuration parameters all of which are declared as constants and immutable so it’s fine. Agree that Objects that are instantiated once per lifetime ≠ Singleton the design pattern.
Umer Mansoor
Immutable objects that store and return constants, are probably okay. I’d still avoid using them as Singletons (i.e. obtaining an instance via the
getInstance()
method) because sometimes in the heat of the moment, it is tempting to introduce mutable state in these objects to finish a feature quickly or to get rid of a bug. If a DI framework is used from the very start, it eliminates this possibility and reduces the risk of being abused.Umer Mansoor
It sounds like what you have is a valid solution that actually has a name in the Design Patterns world. It’s called the “Service Locator” pattern. It uses the Singleton design pattern and it’s probably the only exception I ever make to my “No Singleton / No Static Methods” rule :-)
In general, there are two ways to provide access to this centralized object (which is simply a container of other objects) to classes that need it:
1. Allow the objects that need it to obtain it directly using some sort of
static
method like thegetInstance()
2. Inject it using Dependency Injection.
Both are fine approaches and achieves the same end result: they provide decoupling. I would prefer 2, but 1 is also fine as long as if it’s done correctly and allows itself to mocked in testing (I.e. when I’m testing it, I want to be able to delete everything in the registry, initialize it with stub implementation and then run tests on the methods that I know depend on this registry).
Here are some links to Service Locator:
https://msdn.microsoft.com/…
http://blog.ploeh.dk/2010/0… (Don’t be discouraged by this. If it’s working for you already, it’s better than the best.)
Ned Twigg
A new way to make plain-old singletons testable is durian-globals. All the convenience of singleton, but you can replace or manipulate them within your unit tests.