Виправдане використання множинного наслідування в програмуванні

Немало списів було зломано під час дискусій над цим питанням. Наразі панує думка, що цей прийом дуже шкідливий та робить код аж занадто незрозумілим . До прикладу у мові java воно загалі не реалізоване. Навіть під час навчання часто не наводять зрозумілих прикладів виправданого використання множинного наслідування. Проте такий приклад є і я пропоную розглянути його.

Звернемося до патернів проєктування.

Адаптер – перетворює інтерфейс одного класу на той, на який розраховує клієнт

Адаптери бувають адаптерами об’єктів та адаптерами класів.

Адаптери об’єктів використовують композицію як спосіб адаптації.

<?php
interface Duck {
    public function quack(): void;
    public function fly(): void;
}

class MallardDuck implements Duck {
    public function quack(): void {
        echo "Quack \n";
    }
    public function fly(): void {
        echo "I am flying \n" ;
    }
}

interface Turkey {
    public function gobble(): void;
    public function fly(): void;

}

class WildTurkey implements Turkey {
    public function gobble(): void {
        echo "Gobble \n";   
    }
    public function fly(): void {
        echo "I am flying a short distance \n";
    }    
}

class TurkeyAdapter implements Duck {
    
    private Turkey $turkey;
    
    public function __construct(Turkey $turkey) {
        $this->turkey = $turkey;
    }
    
    public function quack(): void {
        $this->turkey->gobble();
    }
    
    public function fly(): void {
        for ($i = 0; $i < 5; $i++) {
            $this->turkey->fly();
        }
    }
}
$objDuck = new MallardDuck();
$objDuck->quack();
$objDuck->fly();

$objTurkey = new WildTurkey();
$objTurkey->gobble();
$objTurkey->fly();

$objAdapter = new TurkeyAdapter($objTurkey);
$objAdapter->quack();
$objAdapter->fly();

Результат

Quack
I am flying
Gobble
I am flying a short distance
Gobble
I am flying a short distance
I am flying a short distance
I am flying a short distance
I am flying a short distance
I am flying a short distance

Адаптери класів використовують успадкування як механізм адаптації .

<?php
class MallardDuck {
    public function quack(): void {
        echo "Quack \n";
    }
    public function fly(): void {
        echo "I am flying \n" ;
    }
}

trait WildTurkey  {
    public function gobble(): void {
        echo "Gobble \n";   
    }
    public function turkeyFly(): void {
        echo "I am flying a short distance \n";
    }    
}

class TurkeyAdapter extends MallardDuck {
    
    use WildTurkey;
    
    public function quack(): void {
        $this->gobble();
    }
    
    public function fly(): void {
        for ($i = 0; $i < 5; $i++) {
            $this->turkeyFly();
        }
    }
}
$objDuck = new MallardDuck();
$objDuck->quack();
$objDuck->fly();

$objAdapter = new TurkeyAdapter();
$objAdapter->quack();
$objAdapter->fly();


Результат

Quack
I am flying
Gobble
I am flying a short distance
I am flying a short distance
I am flying a short distance
I am flying a short distance
I am flying a short distance

Висновок

Адаптер класів дозволяє не створювати об’єкт WildTurkey, але адаптує лише окремий клас. Як для мене перший варіант все одно кращий, хоча другий теж має право на існування.

Software engineer and consultant

Leave a Reply

Your email address will not be published. Required fields are marked *

*