Decorator Pattern explicat in PHP
Stefanescu Mihai 9 months ago Design PatternsDecorator pattern permite utilizatorului sa adauge functionalitate noua unui obiect deja existent fara sa il modifice. Acesta este un design pattern structural.
Implementare
Vom demonstra implementarea lui folosinde de un exemplu cat se poate de simplu. Presupunand ca facem un site pentru un restaurant si vrem sa calculam pretul pornind de la o pizza de baza + un pret anume pentru fiecare topping.
Intradevar, am putea avea o clasa cu mai multe metode care sa tot adauge valori pe pret, ceva de genul asta, doar acest gen de cod ar ajunge foarte incurcat intr-un timp foarte scurt:
class Pizza { public $cost = 15; public function getCost() { return $this->cost; } public function addCheese() { $this->cost += 5; } public function addMushrooms() { $this->cost += 4; } public function addBacon() { $this->cost += 7; } }
Putem observa din start problema cu acest gen de clasa, pe masura ce avem din ce in ce mai multe topping-uri o sa avem din ce in ce mai multe metode.
In schimb, hai sa facem o clasa cat se poate de simpla numita BasePizza care sa implementeze interfata PizzaInterface care te oblica sa ai metoda getCost, care sa intoarca costul doar pentru o pizza de baza:
interface PizzaInterface { public function getCost(); } class BasePizza implements PizzaInterface { public function getCost() { return 15; } }
Acum, pentru fiecare topping pe care il avem mai cream cate o clasa specifica care sa implementeze interfata definita mai sus (PizzaInterface) si primeste ca parametru in constructor o interfata de tip PizzaInterface astfel:
class CheeseTopping implements PizzaInterface { /** PizzaInterface */ private $pizza; public function __construct(PizzaInterface $pizza) { $this->pizza = $pizza; } public function getCost() { return 5 + $this->pizza->getCost(); } } class BaconTopping implements PizzaInterface { /** PizzaInterface */ private $pizza; public function __construct(PizzaInterface $pizza) { $this->pizza = $pizza; } public function getCost() { return 7 + $this->pizza->getCost(); } }
Acum hai sa vedem ce am facut pana acum. Presupunand ca vreau o pizza de baza pot rula
$basePizza = new BasePizza; echo $basePizza->getCost(); // rezultatul va fi 15 (cel din clasa BasePizza)
Apoi, sa zicem ca vreau un topping, voi avea codul:
$basePizza = new BasePizza; $cheesePizza = new CheeseTopping($basePizza); echo $cheesePizza->getCost();// unde rezultatul va fi 20 (BasePizza 15 + CheeseTopping 5)
Ba chiar mai mult, pot merge asa cat de departe vreau, adaugand "extra" functionalitate unei clase deja existente fara sa o modific:
$basePizza = new BasePizza; $cheesePizza = new CheeseTopping($basePizza); $baconTopping = new BaconTopping($cheesePizza); echo $baconTopping->getCost();