SOLID principles in php

SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 3 Принцип на заместване на Лисков LSP

Част 1 – SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 1 Принцип на единна отговорност

Част 2 – SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 2 Принцип отворено-затворен

Част 3 – SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 3 Принцип на заместване на Лисков

Част 4 – SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 4 Принцип за разделяне на интерфейсите – ISP

Част 5 – SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 5 Принцип на обръщане на зависимостите – DIP

Принципът на заместване на Лисков гласи:

Нека q(x) е доказуемо свойство за обекти от x от тип T. Тогава q(y) трябва да бъде доказуемо за обекти y от тип S, където S е подтип на T.

компютърната програма, ако S е подтип на T, то обектите от тип T могат да бъдат заменени от тези от тип S, без това да намалява функционалностите на програмат

Това означава, че всеки подклас или производен клас трябва да бъде заместим с техния основен или родителски клас.

Изграждайки примерния AreaCalculator клас, помислете за нов VolumeCalculator клас, който разширява AreaCalculator класа:

class VolumeCalculator extends AreaCalculator
{
    public function construct($shapes = [])
    {
        parent::construct($shapes);
    }

    public function sum()
    {
        // logic to calculate the volumes and then return an array of output
        return [$summedData];
    }
}

Припомнете си, че SumCalculatorOutputter класът прилича на това:

class SumCalculatorOutputter {
    protected $calculator;

    public function __constructor(AreaCalculator $calculator) {
        $this->calculator = $calculator;
    }

    public function JSON() {
        $data = array(
            'sum' => $this->calculator->sum();
        );

        return json_encode($data);
    }

    public function HTML() {
        return implode('', array(
            '',
                'Sum of the areas of provided shapes: ',
                $this->calculator->sum(),
            ''
        ));
    }
}

Ако се опитате да изпълните пример като този:

$areas = new AreaCalculator($shapes);
$volumes = new VolumeCalculator($solidShapes);

$output = new SumCalculatorOutputter($areas);
$output2 = new SumCalculatorOutputter($volumes);

Когато извикате HTML метода на $output2 обекта, ще получите E_NOTICE грешка, която ви информира за преобразуване на масив в низ.

За да коригирате това, вместо да връщате масив от VolumeCalculator метода sum на класа, върнете $summedData:

class VolumeCalculator extends AreaCalculator
{
    public function construct($shapes = [])
    {
        parent::construct($shapes);
    }

    public function sum()
    {
        // logic to calculate the volumes and then return a value of output
        return $summedData;
    }
}

В $summedData може да бъде float, двойна или цяло число.

Това удовлетворява принципа на заместване на Лисков.

Забележка

Проблеми при неспазването на Лисков принципа

  • Нарушаваме полиморфизма. – Когато класът наследник не наследява всички функционалности на класа родител.
  • „Поправяне“ чрез type-checking. – Много грешен похват, който чупи принципите на ООП. Ако някога стигнете до момент, в който ви се прииска да го ползвате, замислете се, дали наистина това наистина е нужно, или просто трябва да овъррайднете методите в класовете наследници.

Класически нарушения на Лисков принципа

  • „Type checking“ за различните методи.
  • Овърритън методи, които не са имплементирани.
  • Виртуални методи в конструктора.

Пример за нарушаване на Лисков принципа

Типичен пример за нарушаване на Лисков принципа е, когато имате клас „Квадрат“, който наследява клас „Правоъгълник“. Квадратът в математиката е вид правоъгълник, но в програмирането нещата не стоят точно така. Ако във вашата програма имате квадрат, който наследява правоъгълник, това ще бъде некоректно, защото квадратът ще наследи променливите за ширина и височина на правоъгълника, а всички знаем, че на квадрата всички страни са равни.

При квадрата се приема, че ширината е равна на височината, точно затова и двете променливи приемат стойности едновременно, което предизвиква нежелано и неочаквано действие от програмата, защото в този момент се очаква определеният обект да е правоъгълник, понеже атрибутите на квадрата не могат да приемат стойности по отделно.

Вашият коментар