Sobes.tech
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