The Dependency Inversion Principle states that "Depend upon Abstractions. Do not depend upon concretions". A good real world example of this is plug sockets around your house; any device you buy can be plugged into any socket in your house. You don't have to buy new set of devices when you move house, and you don't have to buy a new house for your devices!
In software terms this means that our higher level classes should not directly depend on lower level classes, but should depend on some intermediary. The same goes for depending on external resources. For example, if you have this class which takes a request string, and deserializes it, and does something with the resulting object:
This has two problems - the first is that it is totally dependant on the
NewtonSoftJson class which means we are in violation of the Dependency Inversion Principle, and also we are tied to a specific provider. We also are using a static method on the
NewtonSoftJson class, which makes the method impossible to test, if we didn't want to depend on
NewtonSoftJson for our test.
We can move towards fixing both of these problems by adding an interface, and depending on that for serialization instead:
By doing this, the
RequestHandler class is now dependant on an abstraction rather than a concretion. This nets us many benefits: We are no longer directly dependant on
OnRequestReceived method has become more testable, and we have also centralised our json serialization logic.
This means that if we wish to change to a different library for json serialization (or use the
IJsonSerializer and pass an instance of the new class to
RequestHandler. It also means that anywhere we want to do json serialization can just take an
IJsonSerializer in as a dependency, and not care what the dependency is actually doing when
Deserialize is called.
Hopefully this explains a little more on how inverting your dependencies can help make your software more flexible, and more maintainable.
All source code is available on my Github: Solid.Demo Source Code