This article discusses the three types of dependency injection: constructor injection, method injection, and property injection, including what they are, how they work, and when to use them.
Abstract
Dependency injection is a technique used to create loosely coupled code by injecting dependencies into a class instead of hardcoding them. The three types of dependency injection are constructor injection, method injection, and property injection. Constructor injection is used when a class has a dependency that it requires in order to work properly. Property injection is used when a dependency is optional and can be changed after the class is instantiated. Method injection is used when the dependency that a class needs will be different much of the time. This article explains when to use each type of dependency injection and provides examples of how to use them.
Bullet points
Dependency injection is a technique used to create loosely coupled code by injecting dependencies into a class instead of hardcoding them.
The three types of dependency injection are constructor injection, method injection, and property injection.
Constructor injection is used when a class has a dependency that it requires in order to work properly.
Property injection is used when a dependency is optional and can be changed after the class is instantiated.
Method injection is used when the dependency that a class needs will be different much of the time.
This article explains when to use each type of dependency injection and provides examples of how to use them.
The 3 Types of Dependency Injection
How and when to use constructor injection, method injection, and property injection
In this article, I’ll discuss the three types of dependency injection — constructor injection, method injection, and property injection— including what they are, how they work, and when to use them.
Constructor Injection
Constructor injection is the process of using the constructor to pass in the dependencies of a class. The dependencies are declared as parameters of the constructor. As a result, you cannot create a new instance of the class without passing in a variable of the type required by the constructor.
That last point is key — when you declare a dependency as a parameter on the constructor, you are saying, “I’m sorry, folks, but if you want to create this class, you must pass in this parameter.” Thus a class is able to specify the dependencies that it requires and be guaranteed that it will get them. You can’t create the class without them. If you have this code:
you can’t create a PayrollSystemwithout passing it an instance of BankingService.(Well, sadly, you can pass null, but we’ll deal with that in a minute.) PayrollSystem very clearly declares that it requires a BankingService, and users of the class must supply one.
Never accept null
As I mentioned, it’s unfortunate that the above class can and will take null as a parameter. I say take because while a user of the class can pass in null, the class itself doesn’t have to accept null.
In fact, I argue that all methods should explicitly reject nullas a value for any reference parameter at any time, including constructors and regular methods. At no time should a parameter allowed to be nullwithout the method raising an exception. If you pass nullto the PayrollSystemabove and the class tries to use it, an error will occur. And errors are bad. They should — and in this case, can — be avoided.
The above code really should look something like this:
This code will never allow the internal field to be null. It will raise an exception if someone dares pass in null as the value for the constructor’s parameter. This is how it should be. You could accept null, but then you’d have to check for it everywhere in your code, and who wants that? In the immortal words of Barney Fife, you should nip the use of nullin the bud by refusing to accept it at the entry point.
Checking for null is boilerplate code. Protecting against nullbeing passed as a parameter is called the guard pattern, and you can write code to guard against null being passed to your methods. Here’s a basic implementation of a guard function:
The guard pattern actually is defined as any Boolean expression that must evaluate to truebefore the program execution can continue. It is usually used to ensure that certain preconditions are met before a method can continue, ensuring that the code that follows can properly execute. Checking that a reference is not nullis probably the most common — but not the only — use for the guard pattern.
In the case at hand, we are using the guard pattern to protect against a parameter being null, so we can use the guard pattern to simplify our code:
When to use constructor injection
You should use constructor injection when your class has a dependency that the class requires in order to work properly. If your class cannot work without a dependency, then inject it via the constructor. If your class needs three dependencies, then demand all three in the constructor.
Additionally, you should use constructor injection when the dependency in question has a lifetime longer than a single method. Dependencies passed into the constructor should be useful to the class in a general way, with its use spanning multiple methods in the class. If a dependency is used in only one spot, method injection (covered below) might be a better choice.
Constructor injection should be the main way that you do dependency injection. It’s simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance. Plus, it’s really simple and clear to do.
Constructor injection should be your go-to technique for clear, decoupled code. But it shouldn’t be the only tool in the toolbox.
Property Injection
Okay, so we use constructor injection when we want to declare required dependencies. But what to do when a dependency isn’t required? Sometimes a class has a dependency that isn’t strictly required but is indeed used by the class. An example might be a document class that may or may not have a grammar checker installed. If there is one, great; the class can use it. If there isn’t one, great — the class can include a default implementation as a placeholder.
The solution here is property injection. You add a property to your class that can be set to a valid instance of the class in question. Since the dependency is a property, you can set it as desired. If the dependency is not wanted or needed, you can leave the property as is. Your code should act as if the dependency is there, so you should provide a do-nothing default implementation so that the code can still be run with or without a real dependency. (Remember, we never want anything to be null, so that default implementation should be valid). Thus, if the user of the class wants to provide a working implementation, they can, but if not, there is a working default that will allow the containing class to still function.
When to use property injection
Use property injection when a dependency is optional and/or when a dependency can be changed after the class is instantiated. Use it when you want users of the containing class to be able to provide their own implementation of the interface in question. You should only use property injection when you can provide a default implementation of the interface in question. Property injection is sometimes referred to as setter injection.
Any default implementation will likely be a non-functional implementation. But it doesn’t have to be. If you want to provide a working default implementation, that’s fine. However, be aware that by using property injection and creating that class in the containing object’s constructor, you are coupling yourself to that implementation.
Example of property injection
An example, of course, will show how things are done. Let’s take a look at code that does what I described above — a document class that has an optional grammar checker.
First, we’ll start with an interface:
Now, we’ll implement it twice: once as a do-nothing default and again as a real grammar checker.
Both of the implementations just log to the console, even the non-op implementation. I merely wanted to make sure that things were all working properly. Again, defaultGrammarCheckeris meant to be a non-operational, default implementation that will keep us from having to check for null all the time.
Now we need a class that has a property on it for the grammar checker.
Here are some things to note about this code:
Its constructor takes the document text as a parameter. It’s then exposed as a read/write property, so you can access it and change it if you want.
The constructor also creates an instance of the default grammar checker. Note again that this creates a hard-coded dependency — one of the perils of property injection. But the dependency is a do-nothing default and prevents us from having constantly to check for null.
The setter for the grammarCheckerproperty contains a guard call, ensuring that the internal value _grammarCheckercan never be null.
One further thing to note is that the grammarCheckerproperty is a write-only property. That is, you can only set the value and never actually read it externally. You might create a write-only property when the value being written is only used internally and will never be called by code outside of the class.
Here’s some code that exercises everything and shows property injection in action:
Here are things to note about the above code:
It creates a document, taking some text as a constructor parameter.
It calls CheckGrammar, but the default grammar checker doesn’t do anything, so it says so in the console.
But then we use property injection to inject a real grammar checker, and when we call CheckGrammar, the grammar gets checked for real.
Thus, property injection allows you to provide optional dependencies. It also allows you to change a dependency if required. For instance, your document class may take texts from different languages and thus will require that the grammar checker changes as the document’s language changes. Property injection will allow for this.
Method Injection
What if the dependency that your class needs is going to be different much of the time? What if the dependency is an interface, and you have several implementations that you may want to pass into the class? You could use property injection, but then you’d be setting the property all the time before calling the method that utilized the frequently changing dependency, setting up the possibility of temporal coupling.
(Temporal coupling is the idea that the order of execution must occur in a specific way for things to work correctly.)
Constructor and property injection are generally used when you have one dependency that isn’t going to change often, so they aren’t appropriate for use when your dependency may be one of many implementations.
This is where method injection comes in.
Method injection allows you to inject a dependency right at the point of use so that you can pass any implementation you want without having to worry about storing it for later use. It’s often used when you pass in other information that needs special handling. For example:
Here we have the notion of a recipe, which may require a different preparer depending on that recipe. Only the calling entity will know what the proper preparer type will be for a given recipe. For instance, one recipe might require a short-order cook, and another recipe might require a baker or a chef. We don’t know when writing the code what kind of IFoodPreparerwill be needed, and thus we can’t really pass the dependency in the constructor and be stuck with that one implementation.
It is also clumsy to set a property every time a new or different IFoodPreparer is required. And setting the property in such a way induces temporal coupling and will suffer from thread-safety issues because it would require a lock around the code in a threaded environment.
The best solution is to just pass the IFoodPreparer into the method at the point of use.
Method injection should be used when the dependency could change with every use, or at least when you can’t be sure which dependency will be needed at the point of use.
Here’s an example of using method injection when the dependency needs to change every time it is used. Imagine a situation where a car-painting robot requires a new paint-gun tip after every car it paints. You might start out like this, using constructor injection:
Here, when we paint the car, we have to get a new paint gun tip. But how? When we paint the car, the tip is no good anymore, but it’s an interface, and we have no way to manually free it, and even if we did, what would we do the next time we need to paint a car? We don’t know what kind of tip is needed for a given car, and if we have properly separated our concerns, we don’t even know anything about creating a new tip. What to do? Well, use method injection instead:
When implementing a method using method injection, you must include a guard clause. The dependency will be immediately used, and, of course, if you try to use it when it’s null, you’ll get an immediate error. This should obviously be avoided.
Now, when we pass the dependency directly to the method, the interface goes out of scope when we are done painting and the paint gun tip is destroyed. In addition, the next time a car needs to be painted, the consumer will pass in a new tip, which will be freed upon use. Method injection to the rescue!
When to use method injection
Thus method injection is useful in two scenarios: when the implementation of a dependency will vary, and when the dependency needs to be renewed after each use.In both cases, it’s up to the caller to decide what implementation to pass to the method.
Conclusion
Dependency injection is a powerful, useful, and critical technique to use in order to write clean, loosely coupled, easy to maintain code. There are three ways to do dependency injection, each having its own use case. Learn when to use these three techniques, and you will be well on your way to writing excellent, testable, and lovely code.