As part of the movement for object oriented design, flexibility for change, and updates to more efficient design.. the dependency inversion principle helps by decoupling software modules. Specifically, high level modules are no longer dependent on the low level module implementations. The net result is a more re-useable high level idea that has easily interchangeable counterparts and details on the low level scale (good for flexibility/change = good for business!). Other examples of patterns besides Dependency Injection that help improve design (to reduce dependency and make separate changeable working parts) include: Plugin and Service Locator.
The following states the theory premises: [See reference 1]
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.
If you do not use the dependency inversion principle, then the high level would conventionally depend on the low level modules. Therefore, if you change the small details of a low level module.. then the big picture becomes something different. And therefore it is more difficult to update and make the system more efficient piece by piece if sections bleed into one another and affect each other directly.
In order to use dependency injection, you need to do a few specific elements.
1. Implementation of service object.
2. Client object (whom depends on the service).
3. Interface (that client uses to access service).
4. Injector object (actually injects service to client). Can be called assembler, provider, container, factory, or spring also.
A few cons of this is that it may require more lines of code to accomplish this task, however this seems to be worthwhile in order to prevent the time in writing a few thousand more lines in the future when things really need to be changed. Encapsulation is reduced because users must now know how the system works and a few more details than otherwise without it. Behavior and construction are separated now which means that there may be many additional files added to a solution and more files must be referred to in order to make the whole system work together properly. I believe these are minor however, and if done neatly and conventionally will be worthwhile design investment in the long run.
There are 3 main types of injections:
1. Constructor: dependencies via class constructor.
2. Setter: client exposes setter method to injector --> injector uses setter to inject dependency.
3. Interface: dependency gives injector method --> inject the dependency --> client (obviously, the interface used must be implementer to expose setter method to accept the dependency).
References:
1. Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike, eds. Head First Design Patterns (paperback) 1. O'REILLY. ISBN 978-0-596-00712-6. Retrieved 2012-06-21.