A common problem that you’ll need to address when designing your systems is dependency.
Software dependency is basically about how much one part of your system relies on another.
When your software is highly coupled, trying to substitute one class or resource for something else is not easily done, or sometimes even possible. To address this issue, we use the Dependency Inversion Principle (DIP), its premise is:
“Depend on abstractions, not on concretions.”
The idea is simple, interfaces and abstract classes are considered high level resources and shouldn’t depend on concrete classes that are considered low-level modules.
An interface or abstract class defines a general set of behaviors, and the concrete classes provide the implementation for these behaviors.
Let’s take a look at some exemples below.
Direct dependency, without DIP:
<?php
class Fan
{
public bool $isOn = false;
public function turnOn(): void
{
$this->isOn = true;
// ...
}
public function turnOff(): void
{
$this->isOn = false;
// ...
}
}
class SwitchButton
{
private Fan $fan;
public function __construct(Fan $fan)
{
$this->fan = $fan;
}
public function toggle(): void
{
if (!$this->fan->isOn) {
$this->fan->turnOn();
} else {
$this->fan->turnOff();
}
}
}Now using Dependency Inversion Principle, DIP:
<?php
//Interface
interface Device
{
public function turnOn(): void;
public function turnOff(): void;
public function isOn(): bool;
}
//Concrete Implementation Device 1 (Fan)
class Fan implements Device
{
private bool $on = false;
public function turnOn(): void
{
$this->on = true;
}
public function turnOff(): void
{
$this->on = false;
}
public function isOn(): bool
{
return $this->on;
}
}
//Concrete Implementation Device 2 (Lamp)
class Lamp implements Device
{
private bool $on = false;
public function turnOn(): void
{
$this->on = true;
}
public function turnOff(): void
{
$this->on = false;
}
public function isOn(): bool
{
return $this->on;
}
}
//High-Level Class (SwitchButton) depending on the interface
class SwitchButton
{
private Device $device;
public function __construct(Device $device)
{
$this->device = $device;
}
public function toggle(): void
{
if (!$this->device->isOn()) {
$this->device->turnOn();
} else {
$this->device->turnOff();
}
}
}Since building a flexible, reusable and maintainable system will prolong the life of your software, applying this design principle will help you achieve those goals.
Leave a Reply