Sobes.tech
Middle

Czym jest dekorator?

sobes.tech AI

Odpowiedź od AI

Dekorator to wzorzec strukturalny, który umożliwia dynamiczne dodawanie nowego zachowania obiektom, opakowując je w specjalne obiekty-dekoratory.

Podstawowe zasady:

  • Kompozycja zamiast dziedziczenia. Dekorator rozszerza funkcjonalność obiektu bez zmiany jego klasy i bez użycia dziedziczenia.
  • Elastyczność. Pozwala na dodawanie lub usuwanie obowiązków obiektu w czasie działania.
  • Zgodność. Dekoratory i opakowywane obiekty mają wspólny interfejs, co pozwala na ich wymienność.

Struktura:

  • Komponent (Component): Interfejs dla obiektów, do których można dynamicznie dodawać obowiązki.
  • Konkretne komponenty (ConcreteComponent): Implementacja komponentu.
  • Dekorator (Decorator): Abstrakcyjna klasa lub interfejs, który rozszerza komponent i zawiera odwołanie do obiektu komponentu.
  • Konkretne dekoratory (Concrete Decorators): Implementacje dekoratora, które dodają konkretne zachowania.

Przykład (Python):

// Interfejs komponentu
class Coffee:
    def get_cost(self):
        pass

    def get_description(self):
        pass

// Konkretne komponenty
class SimpleCoffee(Coffee):
    def get_cost(self):
        return 1.0

    def get_description(self):
        return "Prosta kawa"

// Dekorator bazowy
class CoffeeDecorator(Coffee):
    def __init__(self, decorated_coffee):
        self._decorated_coffee = decorated_coffee

    def get_cost(self):
        return self._decorated_coffee.get_cost()

    def get_description(self):
        return self._decorated_coffee.get_description()

// Konkretne dekoratory (Mleko)
class MilkDecorator(CoffeeDecorator):
    def get_cost(self):
        return self._decorated_coffee.get_cost() + 0.5

    def get_description(self):
        return self._decorated_coffee.get_description() + ", Mleko"

// Użycie
coffee = SimpleCoffee()
print(f"{coffee.get_description()}: ${coffee.get_cost()}") # Prosta kawa: $1.0

coffee_with_milk = MilkDecorator(coffee)
print(f"{coffee_with_milk.get_description()}: ${coffee_with_milk.get_cost()}") # Prosta kawa, Mleko: $1.5

Zalety:

  • Bardziej elastyczny sposób rozszerzania funkcjonalności obiektów niż dziedziczenie.
  • Unika rozrostu podklas związanych z dziedziczeniem.
  • Pozwala na dodanie wielu "warstw" zachowania do jednego obiektu.

Wady:

  • Może skomplikować kod z powodu dużej liczby małych obiektów.
  • Kolejność opakowywania może mieć znaczenie.

Zastosowania w QA / Automatyzacji:

  • Dodanie logowania do istniejących metod bez zmiany ich kodu źródłowego.
  • Implementacja obsługi wyjątków dla określonych wywołań.
  • Dodanie pomiaru czasu lub metryk wydajności.
  • Użycie w bibliotekach automatyzacji testów (np. w wzorcu Page Object do dodawania sprawdzeń lub logowania podczas interakcji z elementami).