Description: dependency injection2e.jpg

From Dependency Injection, Principles, Practices, and Patterns by Steven van Deursen and Mark Seemann

This article delves into the Constructor Injection DI pattern—what it is and how, when, and why to use it.


Take 37% off Dependency Injection, Principles, Practices, and Patterns. Just enter code fccseemann into the discount code box at checkout at manning.com.


How do we guarantee that a necessary dependency is always available to the class we’re currently developing?

By requiring all callers to supply the Dependency as a parameter to the class’s constructor.

When a class requires an instance of a Dependency, you can supply that Dependency through the class’s constructor, enabling it to store the reference for future use.

Definition

Constructor Injection is the act of statically defining the list of required Dependencies by specifying them as parameters to the class’s constructor.

The constructor signature is compiled with the type and it’s available for all to see. It clearly documents that the class requires the Dependencies it requests through its constructor.

The class that needs the Dependency must expose a public constructor that takes an instance of the required Dependency as a constructor argument. This should be the only publicly available constructor. If more than one Dependency is needed, additional constructor arguments can be added to the same constructor. Listing 1 shows the definition of a consuming HomeController class that needs an instance of the IProductService Dependency to work.

Listing 1  Injecting a Dependency using Constructor Injection

  
 public class HomeController
 {
     private readonly IProductService service;            
  
     public HomeController(                               
         IProductService service)                         
     {
         if (service == null)                             
             throw new ArgumentNullException("service");  
  
         this.service = service;                          
     }
 }
  

Private instance field to store supplied Dependency.

Constructor that statically defines its Dependencies.

Argument for supplying the required Dependency.

Guard Clause to prevent clients from passing in null.

Storing the Dependency in the private field for later use. The constructor contains no other logic than verifying and storing its incoming Dependencies.

The IProductService Dependency is a required constructor argument of HomeController; any client that doesn’t supply an instance of IProductService can’t compile, but because an interface is a reference type, a caller can pass in null as an argument to make the calling code compile. You need to protect the class against such misuse with a Guard Clause.[1] Because the combined efforts of the compiler and the Guard Clause guarantee that the constructor argument is valid if no exception is thrown, the constructor can store the Dependency for future use without knowing anything about the real implementation.

Keep the constructor free of any other logic to prevent it from performing any work on Dependencies. The Single Responsibility Principle implies that members should do only one thing. Now that you’re using the constructor to inject Dependencies, you should keep it free of other concerns. This makes the construction of your classes fast and reliable.

When the constructor has returned, the new instance of the class is in a consistent state with a proper instance of its Dependency injected into it. Because the constructed class holds a reference to this Dependency, it can use the Dependency as often as necessary from any of its other members. Its members don’t need to test for null, because the instance is guaranteed to be present.

Constructor Injection should be your default choice for DI. It addresses the most common scenario where a class requires one or more Dependencies.It guarantees that the Dependency must be provided. If the depending class can’t function without the Dependency, such a guarantee’s valuable. Table 1 provides a summary of the advantages and disadvantages of Constructor Injection.

Table 1 Constructor Injection advantages and disadvantages

Advantages

Disadvantages

Injection guaranteed

Easy to implement

Statically declares a class’s Dependencies

Frameworks that apply the Constrained Construction anti-pattern can make using Constructor Injection difficult.

The main disadvantage to Constructor Injection is that if the class you’re building is called by your current application framework, you might need to customize that framework to support it. Some frameworks assume that your classes will have a parameterless constructor. (This is called the Constrained Construction anti-pattern.) In this case, the framework will need special help creating instances when a parameterless constructor isn’t available.

An apparent disadvantage of Constructor Injection is that it requires that the entire Dependency graph be initialized immediately. Although this sounds inefficient, it’s rarely an issue. After all, even for a complex object graph, we’re typically talking about creating a few dozen new object instances, and creating an object instance is something that most platforms and runtimes do extremely fast. Any performance bottleneck your application has will appear in other places. As previously stated, component constructors should be free from all logic except guard checks and storing incoming Dependencies. This makes construction fast and prevents most performance issues.

Constructor Injection is the most generally applicable DI pattern available, and also the easiest to implement correctly. It applies when the Dependency is required.


If you want to learn more about the book, check it out on livebook here.

You can also see other articles on common DI-related topics:
DI intro
Composition Root
Abstract Factories
Method Injection
Service Locator Anti-Pattern
Ambient Context Anti-Pattern

[1] Martin Fowler et al., Refactoring: Improving the Design of Existing Code (Addison-Wesley, 1999), 250.