18 lutego 2020

PHP: SOLID [D] Zasada odwracania zależności

Przyszedł czas na opisanie ostatniej zasady SOLID. Oczywiście jest to literka „D”, zasada w oryginalnej nazwie brzmi:
Dependency Inversion Principle” co tłumaczymy na „Zasada odwracania zależności„.

Wstęp

Treść zasady brzmi następująco:
Wysokopoziomowe moduły nie powinny zależeć od modułów niskopoziomowych – zależności między nimi powinny wynikać z abstrakcji.

Najlepiej od razu przejść do przykładu na którym najprościej zrozumieć zasadę odwracania zależności.

Praktyka

Posłużmy się przykładem inicjowania płatności w naszym systemie.

Klasę inicjującą płatność Pay() można nazwać kodem wysokopoziomowym

class Pay
{
    public $name = 'PayPal';
    private $payment;

    public function __construct(Interfaces\Pay $pay)
    {
        $this->payment = $pay;
    }

    public function implement() : string
    {
        return 'Implementuję płatność: ' . $this->payment->implement();
    }
}

Kod wysokopoziomowy nie powinien zależeć od kodu niskopoziomowego, czyli PayU() oraz PayPal()

class PayPal implements Interfaces\Pay
{
    private $name = 'PayPal';

    public function __construct()
    {
        //kod konstruktora
    }

    public function implement() : string
    {
        return $this->name;
    }
}
class PayU implements Interfaces\Pay
{
    private $name = 'PayU';

    public function __construct()
    {
        //kod konstruktora
    }

    public function implement() : string
    {
        return $this->name;
    }
}

Zależność pomiędzy kodem niskopoziomowym a wysokopoziomowym, powinna wynikać z ich abstrakcji.

Dla nas abstrakcją jest interfejs Pay:

interface Pay
{
    public function implement();
}

Kod sterujący (kontroler):

$methodPay = new Controller\PayPal();
$pay = new Controller\Pay($methodPay);

Do klasy „Pay()” wstrzykujemy zależność („Dependency Injection„), klasa ta spodziewa się obiektu korzystającego z interfejsu „Pay„, ale nie wie jaki rodzaj płatności inicjuje.
Klasie „Pay” tak na prawdę wystarczy wiedza taka, że obiekt jaki otrzymuje korzysta z interfejsu płatności „Pay„, ale wiedza dotycząca konkretnego rodzaju jest już zbędna.

Podsumowanie

Odwrócenie sterowania („IoC„) zostało na powyższym przykładzie rozwiązane za pomocą wstrzyknięcia zależności („DI„). Jest to jednak tylko jedna z możliwości, można bowiem napisać kod zgodny z wzorcem odwrócenia sterowania innymi metodami (wikipedia).