Dependency Inversion Principle or DIP has two key points:
1. Abstractions should not depend upon details;
This principle could be rephrased as use the same level of abstraction at a given level. Interfaces should depend on other interfaces. Don’t add concrete classes to method signatures of an interface. However, use interfaces in your class methods.
Note that Dependency Inversion Principle is not the same as Dependency Injection. Dependency Injection is about how one object knows about another dependent object. In other words, it is about how one object acquires a dependency. On the other hand, DIP is about the level of abstraction. Also, a Dependency Injection Container is a way to auto-wire classes together. That does not mean you do Dependency Injection though. Look at the Service Locatorfor example.
Also, rather than working with classes that are tight coupled, use interfaces. This is called programming to the interface. This reduces dependency on implementation specifics and makes code more reusable. It also ensures that you can replace the implementation without violating the expectations of that interface, according to the Liskov Substitution Principle seen before.