Middle
Jak działa dekorator w PHP?
sobes.tech AI
Odpowiedź od AI
Wzorzec "Dekorator" dynamicznie dodaje nowe zachowanie istniejącemu obiektowi, otaczając go innym obiektem zwanym dekoratorem.
-
Komponenty:
- Interfejs (Component): Deklaruje wspólne metody dla oryginalnego obiektu i jego dekoratorów.
- Konkretny komponent (Concrete Component): Główny obiekt, który ma być dekorowany.
- Podstawowy dekorator (Decorator): Abstrakcyjna klasa lub interfejs zawierający odwołanie do obiektu interfejsu (Component) i implementujący jego metody, zwykle delegując wywołanie do tego obiektu.
- Konkretny dekorator (Concrete Decorators): Implementują nowe możliwości, uzupełniając lub zmieniając zachowanie podstawowego komponentu.
-
Zasada działania:
- Dekorator zawiera odwołanie do obiektu, który dekoruje (kompozycja).
- Posiada tę samą interfejs, co dekorowany obiekt.
- Przy wywołaniu metody na dekoratorze, wykonuje on dodatkową logikę przed lub po wywołaniu odpowiedniej metody na dekorowanym obiekcie, lub całkowicie ją zastępuje (choć to ostatnie nie jest typowym użyciem).
-
Zalety:
- Pozwala na dodawanie funkcjonalności obiektom w czasie działania, a nie statycznie przez dziedziczenie.
- Unika "eksplozji" hierarchii klas przy łączeniu wielu różnych zachowań.
- Umożliwia tworzenie elastycznych kombinacji zachowań.
-
Przykład:
<?php
// Interfejs komponentu
interface Coffee {
public function getCost(): float;
public function getDescription(): string;
}
// Konkretny komponent
class SimpleCoffee implements Coffee {
public function getCost(): float {
return 5.0;
}
public function getDescription(): string {
return "Prosta kawa";
}
}
// Podstawowy dekorator
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();
}
}
// Konkretny dekorator: Dodanie mleka
class MilkDecorator extends CoffeeDecorator {
public function getCost(): float {
return parent::getCost() + 2.0;
}
public function getDescription(): string {
return parent::getDescription() . ", z mlekiem";
}
}
// Konkretny dekorator: Dodanie cukru
class SugarDecorator extends CoffeeDecorator {
public function getCost(): float {
return parent::getCost() + 1.0;
}
public function getDescription(): string {
return parent::getDescription() . ", z cukrem";
}
}
// Użycie:
// Tworzymy prostą kawę
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " - " . $coffee->getCost() . "\n"; // Prosta kawa - 5
// Dodajemy mleko
$coffeeWithMilk = new MilkDecorator($coffee);
echo $coffeeWithMilk->getDescription() . " - " . $coffeeWithMilk->getCost() . "\n"; // Prosta kawa, z mlekiem - 7
// Dodajemy cukier
$coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk);
echo $coffeeWithMilkAndSugar->getDescription() . " - " . $coffeeWithMilkAndSugar->getCost() . "\n"; // Prosta kawa, z mlekiem, z cukrem - 8