Authors: Paul Hammant
Inversion of Control (IoC) is a design pattern that addresses a component's dependency resolution, configuration and lifecycle. Note to confuse things slightly, IoC is also relevant to simple classes, not just components, but we will refer to components throughout this text. The most significant aspect to IoC is dependency resolution and most of the discussion surrounding IoC dwells solely on that.
Types of IoC
There are many types of IoC, but we'll concentrate on the type of IoC that PicoContainer introduced to the community. Formerly known as type-3, now known as Constructor Injection. We'll ignore Setter Injection and Contextualized Lookup as they are described in the IoC Types page.
One well-known synonym for IoC is DIP - described in Robert C. Martin's excellent Dependency Inversion Principle paper.
A second nickname for IoC is The Hollywood Principle (Don't call us we'll call you).
Some detail about the history of Inversion of Control - IoC History
It generally favors loose coupling between components. Loose coupling in turn favours:
- More reusable classes
- Classes that are easier to test
- Systems that are easier to assemble and configure
Simply put, a component designed according to IoC does not go off and get other components that it needs in order to do its job. It instead declares these dependencies, and the container supplies them. Thus the name IoC/DIP/Hollywood Principle. The control of the dependencies for a given component is inverted. It is no longer the component itself that establishes its own dependencies, but something on the outside. That something could be a container like PicoContainer, but could easily be normal code instantiating the component in an embedded sense.
Here is the simplest possible IoC component :
Here are some common smells that should lead you to refactor to IoC :
The problem is that you are tied to the OrangleImpl implementation for provision of Orange services. Simply put, the above apple cannot be a (configurable) component. It's an application. All hard coded. Not reusable. It is going to be very difficult to have multiple instances in the same classloader with different assembly.
Here are some other smells along the same line :
Sometimes we see configuration like so ...
In the IoC world, it might be better to see the following for simple component designs :
Or this for more complex ones, or ones designed to be more open to reimplementation ..
With the latter design there could be many different implementations of BigFatComponentConfig. Implementations such as:
- Hard coded (a default impl)
- Implementations that take config from an XML document (file, URL based or inlined in using class)
- Properties File.
It is the deployer's, embeddor's or container maker's choice on which to use.
Simply put, the lifecycle of a component is what happens to it in a controlled sense after it has been instantiated. Say a component has to start threads, do some timed activity or listen on a socket. The component, if not IoC, might do its start in its contructor. Better would be to honor some start/stop functionality from an interface, and have the container or embeddor manage the starting and stopping when they feel it is appropriate:
The lifecycle interfaces for PicoContainer are the only characterising API elements for a component. If Startable was in the JDK, there would be no need for this. Sadly, it also menas that every framework team has to write their own Startable interface.
The vast majority of components do not require lifecycle functionality, and thus don't have to implement anything.
Of course, in all of these discussions, it is important to point out that logging is a common exception to the IoC rule. Apache has two static logging frameworks that are in common use: Commons-Logging and Log4J. Neither of these is designed along IoC lines. Their typical use is static accessed whenever it is felt appropriate in an application. Whilst static logging is common, the PicoContainer team do not recommend that developers of reusable components include a logging choice. We suggest instead that a Monitor component interface is created and default adapters are provided to a number of the logging frameworks are provided.