For example, if Class A has a dependency on Class B, refactoring this via dependency inversion would result in Class A depending on Interface B which is implemented by Class B.
- Before refactoring: Class A ---> Class B
- After refactoring: Class A ---> Interface B <--- Class B
In a nutshell, the dependency inversion principle states that both your high level abstractions (in example, Class A) and your low level abstractions (in example, Class B) should not depend on something concrete (as Class A depended on Class B before refactoring), but be decoupled by a middle abstract layer (the Interface B abstraction).
Dependency inversion is used as a means of implementing dependency injection. For example, in Spring,
interface AbstractB {
}
@Component
class ConcreteB implements AbstractB {
}
@Component
class ConcreteA {
@Autowired
// note reference type is AbstractB
private AbstractB concreteB;
}
- By depending on a reference of type AbstractB (instead of ConcreteB) in ConcreteA, we are applying dependency inversion.
- By using @Autowired and letting Spring inject that dependency for us (instead of instantiating it ourselves with the 'new' keyword) we are using dependency injection.
- Inversion of control is the principle of allowing an external framework (in this example, the Spring IoC container) to instantiate your dependencies and inject them into your code.
Regarding 'Do we achieve IOC using the DIP as well?', in my opinion, not necessarily, since we could autowire with a Reference of type ConcreteB, achieving IoC and DI but violating DIP.
Does this answer your question?