Sobes.tech
Middle

Как работи декораторът в PHP?

sobes.tech AI

Отговор от AI

Моделът "Декоратор" динамично добавя ново поведение към съществуващ обект, като го обвива в друг обект, наречен декоратор.

  • Компоненти:

    • Интерфейс (Component): Обявява общи методи за оригиналния обект и неговите декоратори.
    • Конкретен компонент (Concrete Component): Основният обект, който трябва да бъде декориран.
    • Базов декоратор (Decorator): Абстрактен клас или интерфейс, който съдържа препратка към обект от интерфейса (Component) и реализира неговите методи, обикновено делегирайки извикването на този обект.
    • Конкретни декоратори (Concrete Decorators): Реализират нови възможности, допълвайки или променяйки поведението на базовия компонент.
  • Принцип на работа:

    • Декоратор съдържа препратка към обекта, който декорира (композиция).
    • Декоратор има същия интерфейс, като декорирания обект.
    • При извикване на метод при декоратора, той или изпълнява допълнителна логика преди или след извикването на съответния метод на декорирания обект, или го заменя изцяло (макар последното да не е типично използване).
  • Предимства:

    • Позволява добавяне на функционалност към обекти по време на изпълнение, а не чрез статично наследяване.
    • Избягва "взривяване" на йерархията на класовете при комбиниране на различни поведения.
    • Позволява създаване на гъвкави комбинации от поведения.
  • Пример:

<?php

// Интерфейс на компонента
interface Coffee {
    public function getCost(): float;
    public function getDescription(): string;
}

// Конкретен компонент
class SimpleCoffee implements Coffee {
    public function getCost(): float {
        return 5.0;
    }

    public function getDescription(): string {
        return "Обикновен кафе";
    }
}

// Абстрактен декоратор
abstract class CoffeeDecorator implements Coffee {
    protected Coffee $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }

    public function getCost(): float {
        return $this->coffee->getCost();
    }

    public function getDescription(): string {
        return $this->coffee->getDescription();
    }
}

// Конкретен декоратор: добавяне на мляко
class MilkDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 2.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", с мляко";
    }
}

// Конкретен декоратор: добавяне на захар
class SugarDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 1.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", със захар";
    }
}

// Използване:
// Създаване на обикновено кафе
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " - " . $coffee->getCost() . "\n"; // Обикновено кафе - 5

// Добавяне на мляко
$coffeeWithMilk = new MilkDecorator($coffee);
echo $coffeeWithMilk->getDescription() . " - " . $coffeeWithMilk->getCost() . "\n"; // Обикновено кафе, с мляко - 7

// Добавяне на захар
$coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk);
echo $coffeeWithMilkAndSugar->getDescription() . " - " . $coffeeWithMilkAndSugar->getCost() . "\n"; // Обикновено кафе, с мляко, със захар - 8