Что такое паттерн Декоратор (Decorator)?

«Что такое паттерн Декоратор (Decorator)?» — вопрос из категории Паттерны проектирования, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Декоратор — структурный паттерн проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные "обёртки". Он является гибкой альтернативой наследованию для расширения поведения.

Аналогия из тестирования: Представьте базовый тест-кейс. Вы можете "декорировать" его:

  • Добавить логирование шагов (LoggingTestCaseDecorator).
  • Добавить повторение при неудаче (RetryTestCaseDecorator).
  • Добавить снятие скриншота при падении (ScreenshotOnFailDecorator). Каждый декоратор добавляет своё поведение, не меняя исходный тест-кейс.

Ключевые компоненты:

  1. Компонент (Component): Общий интерфейс для объектов, которые можно декорировать.
  2. Конкретный компонент (ConcreteComponent): Исходный объект, который нужно расширить.
  3. Декоратор (Decorator): Класс, реализующий тот же интерфейс, что и Component, и содержащий ссылку на него.
  4. Конкретные декораторы (ConcreteDecorators): Добавляют конкретную функциональность.

Пример на Python (упрощённо):

# Компонент - базовый тест
class TestCase:
    def run(self):
        print("Выполнение базового теста...")

# Базовый декоратор
class TestCaseDecorator(TestCase):
    def __init__(self, test_case):
        self._test_case = test_case
    def run(self):
        self._test_case.run()

# Конкретные декораторы
class LoggingDecorator(TestCaseDecorator):
    def run(self):
        print("[LOG] Начало выполнения теста")
        super().run()
        print("[LOG] Конец выполнения теста")

class RetryDecorator(TestCaseDecorator):
    def run(self, max_attempts=3):
        for attempt in range(1, max_attempts + 1):
            print(f"Попытка {attempt}...")
            # Здесь была бы логика запуска и проверки результата
            super().run()
            # if test_passed: break

# Использование
simple_test = TestCase()
decked_out_test = RetryDecorator(LoggingDecorator(simple_test))
decked_out_test.run()

Плюсы для QA: Повышение переиспользуемости кода тестов, гибкость в комбинировании поведения (логирование + повтор + скриншот), соблюдение принципа единственной ответственности (Single Responsibility Principle).