Factories and Dependency Injectors
14 July 2014
It seems that over the years, many people have accepted that Dependency Injection (DI), which is sometimes called Inversion of Control (IoC), is a "good thing" and that they should be "doing it." But, few of those that I talk to seem to know why that is. And, fewer still can tell you the difference between the Factory Pattern and DI. This is usually an indicator of how they (mis)utilize their DI framework. Many of the implementations that I have seen use it as a glorified factory. But, DI is a special implementation of the factory pattern that can do so many more things to help improve the structure of your code and improve testability than just serving out objects. The relationship between the factory pattern and DI is like the relationship between rectangles and squares. All squares are rectangles, but a rectangle is not necessarily a square. Just like all DI frameworks follow the factory pattern, but a factory is not necessarily a DI container.
To prove my point about most implementations under utilizing DI containers, here is a typical example using Castle Windsor:
There is absolutely no difference between the implementation above and a simple factory (other than it is using a fancy framework). The key to leveraging DI and making it more than just a factory is to use it not only for managing your dependencies, but also to manage the dependencies of your dependencies.
The best way that I know of to manage both your dependencies and their dependencies is by using constructor injection. This is a pattern where abstractions (i.e. interface or abstract base class) of your dependencies are passed into the constructor of the class you would like to get from the DI container. All DI frameworks will populate these abstractions when resolving the object you are trying to retrieve from the container (provided those abstractions are also registered with the container).
With constructor injection, the consumer behaves the same as in the earlier example. But, you can easily have one implementation of your abstracted dependencies for your production code and a different implementation for your tests. The test implementation can be a fake or a mock. (I typically use fakes, but mocks do have their place.) This allows you to create a true unit test and not simply an integration test using a TDD/BDD framework.
Using this pattern, you could also have multiple test abstractions to handle different scenarios or user stories. Notice that the unit test above is not testing the validity of the order, the functionality in the (fake) validator, or the (fake) repository. The test's **single responsibility* is to make sure that the OrderPlacementCommand is validating the order before trying to save it via the repository.* Too often, I see developers trying to test more than one thing at a time. Generally, this is either because they do not know the difference between a unit test and an integration test or, more commonly, they do not know how to properly manage their dependencies in such a way that the unit tests can be broken down into actual units. Breaking functionality down into dependencies made up of cohesive classes and methods that do one thing each and then managing those dependencies is the most difficult thing to master when writing unit tests.(Remember this if you ever find yourself being interviewed by me.)
Other Differences Between DI and a Simple Factory
DI frameworks typically have other features that can be used over and above what the factory pattern prescribes. This article will not go any further than to mention them, but I hope to dive deeper into each of them in later articles.
- DI frameworks allow you to easily manage the life-cycle of your objects (i.e. singleton, per-resolve, per-session, per-web-request). This is particularly useful when managing database connections.
- DI frameworks can allow you to additively modify the behavior of your application without recompiling.
- DI frameworks can easily be configured to inject additional functionality using an Aspect Oriented Programming (AOP) framework.
DI is a powerful pattern that can help you improve the structure of your code and lower testing friction. But, like any tool, you need to know how to leverage DI to get the real benefits. Constructor Injection is one way that you can make your DI experience more effective, and can improve the testability of your code with or without DI. Both of these patterns help you to decouple your code to improve the extensibility and maintainability of your application.
is licensed under a Creative Commons Attribution 4.0 International License