Introducing Dependency Inversion0:00
The fourth solid principle we'll explore is Dependency Inversion Principle. According to this principle, a high-level code should not depend on a low-level code. Both should depend on abstractions. I know, it's a very abstract definition. But a good metaphor for this can be the wiring in your home and the use of electricity. The wires behind the walls are the low-level modules. You don't need to know what you have there or how it all works to use electricity. You just have a socket that gives you the service you need. Lights on or lights off. This is your high-level module.
Lights on or lights off. This is your high-level module. Now, back to our payment example. The low-level modules are the concrete payment classes: Wire and Payoneer. These have the exact implementation of the specific payments, just like the wires behind the wall. Our high-level module, on the other hand, is the controller. The controller receives the user input over here and decides which implementation to use or what to rely on.
Identifying Concrete Dependencies0:58
The controller receives the user input over here and decides which implementation to use or what to rely on to return the expected response. Now, if we look at the controller, we'll see that it depends on our low-level modules. It depends on Wire and Payoneer. This would be something like you digging into that wall to trigger the right wired that turns the electricity on. Apart from the controller that depends on the concrete service classes, we also have the service classes depending on a concrete repository class.
Apart from the controller that depends on the concrete service classes, we also have the service classes depending on a concrete repository class. So, over here, our Payoneer class depends directly on the PayoneerRepository. And the Wire class depends on the WireRepository. They depend on the concrete implementation, not the abstraction. And the issue with this can come during testing because we would be unable to mock the dependency. So, we do want to depend on the abstraction here to make it easier to test. And in addition to this, in the future,
to make it easier to test. And in addition to this, in the future, if our product scales massively and we see that we have a need for a more scalable infrastructure around the database, using abstractions here would make it much easier to replace this concrete implementation than if we would be relying on the concrete repository classes as we do now. The way to improve all of this is to invert the dependencies so that all of our concrete implementations,
Inverting via Interfaces2:19
The way to improve all of this is to invert the dependencies so that all of our concrete implementations, the low-level and high-level modules, all of them will depend on the interfaces instead of the concrete implementation. They know exactly what they can use to handle the wanted action, and we can easily interchange concrete implementations without affecting the whole system. We'll start by abstracting our repositories because we still haven't created interfaces for this part.
Creating Repository Interfaces2:40
We'll start by abstracting our repositories because we still haven't created interfaces for this part. We'll create a new file under Contracts and name it WireRepository. Now, my namespace here would be Contracts. We're creating an interface, WireRepositoryInterface. We have to getFields, getValues, store, delete, makePrimer. This is good. We want the same for Pioneer. Now, considering the simplicity of our example, these are not the same, but in reality,
Now, considering the simplicity of our example, these are not the same, but in reality, you would likely have multiple other methods that are specific to the concrete repository, so that is why we want to outline the interfaces separately. For now, let's just keep it as is. Next, I want to open my PioneerRepository and say this one implements the interface. We're good. We'll use my interface over here.
We're good. We'll use my interface over here. Next, we'll do the same for WireRepository. Use WireInterface, and then I want it to implement the said interface. What we want to do now is invert the dependencies. Everywhere where we have a dependency on the concrete WireRepository class, we want to depend on the WireRepository interface. In the same regard, wherever we depend
Refactoring Services to Interfaces4:21
we want to depend on the WireRepository interface. In the same regard, wherever we depend on the ConcretePioneerRepository class, we want to depend on the interface. Let's first open our WireService class. We have the WireRepository referenced here. We want to replace that with the interface, so we have WireRepository interface, and then instead of including the concrete repository, I want to include the interface here.
Binding Interfaces in Laravel4:46
and then instead of including the concrete repository, I want to include the interface here. Let's do the same for Pioneer. Instead of PioneerRepository, I have PioneerRepository interface, and I will use the interface instead of the repository. Finally, for all of this to work, we need to bind the concrete implementations to the abstractions using the ServiceProvider. Open AppServiceProvider in the register method over here.
to the abstractions using the ServiceProvider. Open AppServiceProvider in the register method over here. Actually, let's first add the interfaces here and also the classes. Now we have WireRepository interface. We'll bind it to the WireRepository concrete class, and we'll do the same for Pioneer. So now we tell Laravel to resolve this for us whenever we rely on the PioneerRepository interface. In the background, we want to actually create
whenever we rely on the PioneerRepository interface. In the background, we want to actually create an instance of the PioneerRepository. The good thing about this is in your tests, you would change the concrete implementation of PioneerRepository to a mock class that will allow you to test without actually depending on a database. Okay, I have my Pioneer page. I will move this back to test.
Okay, I have my Pioneer page. I will move this back to test. It works!
