I spent a few weeks earlier this year doing some research on Castle Windsor (a specific IOC container) to implement it into a solution at work. In this and future posts, I plan to discuss some of the things I’ve learned over the course of that research.
Inversion of control (IOC) is a way to link together classes with different dependencies at run time instead of explicitly creating the dependencies in code. A good analogy to think of is an IOC container is like glue. It can take classes built in code and combine them together to construct one or more objects. It doesn’t really add functionality to the application, but instead binds and holds everything together.
Dependency injection and inversion of control often get confused and interchanged as terms. I like to think of it this way. Dependency injection is really an abstract design pattern used in a class by class basis. It allows other objects to be “injected” or passed into an individual class. IOC is a pattern whereby a container takes a plethora of classes and combines them all together to construct some object tree from them all, thereby making dependency injection easier to fulfill. The container for the IOC pattern is often structured using a factory design pattern.
Imagine there are several classes all utilizing dependency injection. Each class has 2 or 3 parameters. Now, for every class that needs to be constructed for each parameter passed in, those also have parameters that need to be constructed and passed in. This get’s complex fast. Just think of it as a huge object tree that continues to get linked and put together. The more complex the program, the larger the number of dependencies to fulfill, and the more difficult the object tree becomes to construct.
This is where IOC steps in to help. By relying on the IOC container, it can resolve those references and automatically create the objects for us after it has been properly configured.
IOC containers work in a 3 step process.
- Component registration, also known as installation in some frameworks
- Object resolution, also known as resolving, or constructing an object
- Disposal of objects
Here’s a brief description of each step. I will post some more concrete examples of working with Castle Windsor later which should help these make more sense.
In the registration process a set of rules are defined which determine where a specific implementation of a class will map. For example, let’s say we are using the FordTaurus example from my dependency injection post. We could tell the container that whenever it encounters an Engine class, it should construct a V6Engine for it.
In the object resolution process, this is where most of the work for the container will go. Typically this is one or more calls to have the container construct some object for the program. The container will resolve any unknown classes and pass them in as appropriate as defined by the registration process.
The last step is to dispose of the objects. This is either telling the container to release the object so it isn’t tracked anymore, or to simply do any clean up logic for the object itself.
The concept seems very abstract at first. In a future post, I will show an example and put this into action. Hopefully, you will be able to see the benefits and be able to try it out in your next project too.