Menu
Coddy logo textTech

Wzorzec dekoratora

Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 96 z 110.

Wzorzec Dekorator pozwala dynamicznie dodawać nowe zachowania do obiektów przez opakowywanie ich w specjalne obiekty nazywane dekoratorami. W przeciwieństwie do dziedziczenia, które dodaje zachowanie na etapie kompilacji, dekoratory dołączają dodatkowe obowiązki w czasie wykonywania, nie modyfikując oryginalnej klasy.

Kluczowa idea polega na tym, że zarówno oryginalny obiekt, jak i dekoratory implementują ten sam interfejs.

Dekorator opakowuje oryginalny obiekt, deleguje do niego i dodaje własne zachowanie przed jego działaniem lub po nim:

abstract class Coffee {
  String getDescription();
  double getCost();
}

class SimpleCoffee implements Coffee {
  @override
  String getDescription() => 'Simple Coffee';

  @override
  double getCost() => 2.0;
}

class MilkDecorator implements Coffee {
  final Coffee _coffee;
  MilkDecorator(this._coffee);

  @override
  String getDescription() => '${_coffee.getDescription()}, Milk';

  @override
  double getCost() => _coffee.getCost() + 0.5;
}

class SugarDecorator implements Coffee {
  final Coffee _coffee;
  SugarDecorator(this._coffee);

  @override
  String getDescription() => '${_coffee.getDescription()}, Sugar';

  @override
  double getCost() => _coffee.getCost() + 0.2;
}

void main() {
  Coffee coffee = SimpleCoffee();
  coffee = MilkDecorator(coffee);
  coffee = SugarDecorator(coffee);

  print(coffee.getDescription());  // Prosta kawa, mleko, cukier
  print(coffee.getCost());         // 2.7
}

Każdy dekorator opakowuje poprzedni obiekt i wzbogaca go o dodatkowe możliwości. Możesz łączyć wiele dekoratorów w dowolnej kombinacji, uzyskując elastyczne zachowanie bez tworzenia podklasy dla każdej możliwej kombinacji. Ten wzorzec sprawdza się idealnie, gdy chcesz dodawać funkcje do obiektów bez wpływania na inne obiekty tej samej klasy.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system zamawiania pizzy przy użyciu wzorca Dekorator! Utworzysz bazową pizzę, którą można wzbogacać o różne dodatki. Każdy dodatek opakowuje poprzedni element i wpływa zarówno na opis, jak i na cenę.

Podzielisz kod na dwa pliki:

  • pizza.dart: Ten plik zawiera interfejs pizzy i wszystkie klasy dekoratorów. Zacznij od klasy abstrakcyjnej Pizza, która definiuje dwie metody: String getDescription() i double getPrice(). Następnie utwórz klasę PlainPizza, która implementuje Pizza — zwraca Plain Pizza jako opis i kosztuje 8.0. Teraz utwórz trzy klasy dekoratorów, z których każda opakowuje Pizza i ją wzbogaca:
    • CheeseDecorator — dodaje , Cheese do opisu i 1.5 do ceny
    • PepperoniDecorator — dodaje , Pepperoni do opisu i 2.0 do ceny
    • MushroomDecorator — dodaje , Mushrooms do opisu i 1.25 do ceny
    Każdy dekorator powinien implementować Pizza, przyjmować Pizza w konstruktorze i delegować wywołania do opakowanej pizzy, zanim doda własny składnik.
  • main.dart: Zaimportuj plik z pizzą i pokaż, jak dekoratory nakładają się na siebie, tworząc spersonalizowane zamówienie. Zacznij od PlainPizza, następnie opakuj ją w CheeseDecorator, potem opakuj ją w PepperoniDecorator, a na koniec opakuj całość w MushroomDecorator. Wypisz opis gotowej pizzy, a następnie wypisz Total: $, po którym podaj cenę.

Zauważ, jak każdy dekorator bazuje na poprzednim — nakładając na siebie proste dekoratory o pojedynczej odpowiedzialności, tworzysz pizzę ze wszystkimi dodatkami!

Oczekiwany wynik:

Plain Pizza, Cheese, Pepperoni, Mushrooms
Total: $12.75

Spróbuj swoich sił

import 'pizza.dart';

void main() {
  // TODO: Utwórz PlainPizza
  
  // TODO: Owiń ją za pomocą CheeseDecorator
  
  // TODO: Owiń ją następnie za pomocą PepperoniDecorator
  
  // TODO: Owiń całość za pomocą MushroomDecorator
  
  // TODO: Wypisz opis gotowej pizzy
  
  // TODO: Wypisz "Total: $", a następnie cenę
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Dart online