Singleton or Dependency Injection?
Singleton or Dependency Injection?
Design patterns in software engineering provide a common way of resolving specific problems that share a common context. It only pertains to the approach of solving the problem but not necessarily providing the solution by itself. The pattern can be focused on one or more design criteria. It can be used to improve the structural organization of the code components for maintainability, decouple components and promote encapsulation or thrive on object lifecycle management and instantiation for performance considerations. To consume a design pattern, we should understand its main objective of the pattern as well as the building blocks and the underlying principles associated with it.
Whenever we develop complex applications, we usually catch ourselves asking whether we should use Singleton or Dependency Injection? In this article, we will try to answer that and also illustrate the two major patterns, the principles behind them as well as the areas where they are commonly applied. We will also tackle the difference between these two patterns and how related are they to each other. Along the way, we will show some code samples to supplement the fundamental idea that we are trying to demonstrate.
Singleton Pattern
This pattern ensures that there is one and only one object instance of the given class which will be used for the entire life cycle of the consuming application. The instantiation of the class should only happen when the need for the object arise. The latter principle is called lazy object instantiation. There are lots of different ways to implement singleton but in .NET 4.0, it can be easily implemented as shown below:
In the example above, the pattern demonstrates the following principles and characteristics:
- Only one instance exist
- Lazily created / Only created when needed
- Single constructor which is private and parameter less
- Prevents other classes from instantiating it
- Prevents sub-classing
- Class should be sealed
- A static variable which holds a reference to the static instance
- A publicly accessible reference to the static instance.
- Uses double check locking
- Uses static constructor
This pattern is highly applicable on factory classes which are responsible for generating instances of objects, component managers and other global objects that need to be accessed across the application.
See related article for further details.
Dependency Injection Pattern
When designing complex applications, we usually encounter components with multiple interrelated and dependent components. Resolving dependencies between these components is one of the key factors to the success or failure of the application.
Dependency Injection pattern tries to remove the high coupling between multiple interrelated components at runtime. This is very helpful especially with unit testing as we can isolate component dependencies and replace them with stub or mock objects. Today, we usually inject those dependencies using containers which are responsible for creating component instances.
The example below shows a class(“DependentObject”) that is dependent on a specific interface(“ISampleImpl”). At runtime, the ISampleImpl can be resolved using an IOC container and be replaced with an actual implementation class instance. This way, there is no hard-coded dependency between the DependentObject and the actual implementation of the ISampleImpl interface.
This pattern is highly applicable on complex components that are dependent on multiple related component instances.
Singleton or Dependency Injection?
Using the details illustrated in the previous sections, it is apparent that these two patterns are solving two different problems and cannot be directly compared. We can use both patterns in our application but we have to balance the benefit that we are getting out of it and the complexity that we are introducing whichever path we chose.
The example above shows the following characteristics:
- Dependency injection using IOC provides the concrete implementation to the dependent object and uses multiple object instances
- Singleton uses only one instance of the object
- How we can inject a singleton instance to a dependent object.
The second example shows how you can use singleton and dependency injection by specifying the component's lifestyle as 'singleton' in the DI framework's configuration file. In this approach, you don't have to worry about how to instantiate the singleton object yourself since it will be handled by the framework itself.
<component id="componentid"
service="ServiceNamespace, ServiceAssembly"
type="ServiceNamespace.Component, ServiceAssembly"
lifestyle="singleton">
</component>
I hope this article helps you to decide whether you will use Singleton pattern for components that requires a single instance and Dependency Injection/IOC for resolving component dependencies or use both to satisfy both requirements.