Now let's move on to the last one of the five solid principles.
So we're talking about D right D and solid dependency inversion principle or in short dip.
And we use the dependency inversion principle to reduce the coupling between high level and low level
modules.
So here I have prepared another application.
This one is quite simple.
We have a class called Email service public void send email.
Usually any service that you create in your application will be a low level module because it offers
generic functionality like or core functionality like sending emails, low level.
And then we have a notification which is like using that email service.
It relies on the email service and therefore it's a high level module.
Now as I said, we use Dip dependency inversion principle to reduce the coupling between both of them.
Here we have the notification and here we can see the violation of that principle.
So our notification class is using an email service as a private field based on that class.
So we require an instance of the email service class here that's hard coded right.
Like we're not using an abstract version or an interface.
We rely exactly on that email service class.
Then inside of the constructor of our notification class, we directly create that instance of that
email service.
So our high level module the notification creates a low module or low level module instance.
The email service right here we're using the new keyword.
So again inside of our high level module notification we create an instance of a low level module our
email service.
And that's the violation.
That should not happen.
A high level module should not create an instance of a low level module like our email service here.
So now it's time to reduce the coupling here.
Our goal is that we can submit an email service to our notification without using the class directly.
We want to use an abstract version such as an interface for example.
So the first thing that we need to do is to create an interface for our email service.
Public interface I email service.
So we create a dedicated interface for this specific service.
For our email service.
Let's take the signature here public void send email.
Right.
So we create the contract or the interface.
Now we implement the interface and create the contract.
So our email service has to use the send email method or has to implement it.
Totally fine.
Nothing new.
We have just created an interface.
And now the magic happens where we can start decoupling.
When we go to our notification class here again to our high level module, we want to get rid of this
right.
We do not want to create an instance of an email service award.
So therefore we will now switch our email service here to an email service instead.
So to an abstract version, an interface here.
Right.
So it's not based on the class.
And then we say I email service.
And here inside of our constructor we now receive an I email service instance right email service without
an underscore.
And then we simply assign the value from the constructor.
So the parameter here our email service to our private field email service.
Now we are not creating an instance of a low level module inside of a high level module.
So that's totally fine.
You can still see that we can use our email service here, right?
With an interface we can send email.
And now if we go to our application we are not creating a new notification just like that.
But we have to submit an email service now.
So let's go ahead and create an eye email service.
Email service equals to new email service.
Just like this.
We take our email service, paste it in our notification and have entirely decoupled it.
So in that way you will be also able to provide some more mock information, right?
If we would bind it hardcoded to our class, our email service class, you would always have to create
exactly an instance of that email service class.
But in real world when we create unit tests, for example, or just a class for mock, you could now
create.
And that's the key part.
Pay attention.
That's why it's so important.
Public class mock email service.
That one is just for testing purposes right.
Mock email service and it implements the eye email service.
Therefore we have to implement.
Let's just take a look here.
Show potential fixes.
Implement the interface that sent email method.
And now from another testing project that we would have in our solution, we could simply create a new
mock email service and the code runs fine.
It you know, there is no issue, no implementation issue because we have made use of the dependency
inversion principle so that high level functionality is not coupled to low level functionality.
Cool.
Alrighty, so that is the dependency inversion principle or Dip.
You should always keep in mind if you have a service, for example, which offers low level functionality
or is a low level module, and you create something on a higher level which relies on that one, make
sure that you are not strictly coupling it right.
Instead, make use of abstract or interfaces.