Виправдане використання множинного наслідування в програмуванні
Немало списів було зломано під час дискусій над цим питанням. Наразі панує думка, що цей прийом дуже шкідливий та робить код аж занадто незрозумілим . До прикладу у мові 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, але адаптує лише окремий клас. Як для мене перший варіант все одно кращий, хоча другий теж має право на існування.