Webmaster общности: Predpriemach.com | SearchEngines.bg

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

    php-solid-principles

    Част 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“ за различните методи.
    • Овърритън методи, които не са имплементирани.
    • Виртуални методи в конструктора.

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

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

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