Decorator Pattern

Паттерн Декоратор для динамического добавления функциональности объектам

Паттерн Декоратор (Decorator Pattern) позволяет динамически добавлять новую функциональность объектам, оборачивая их в декораторы, не изменяя их структуру. Это альтернатива наследованию, которая обеспечивает большую гибкость. Декоратор имеет тот же интерфейс, что и декорируемый объект, и делегирует вызовы исходному объекту, добавляя свою логику до или после.

В примере ниже базовый класс Car может быть обернут декораторами AutoPilot и Spoiler, которые добавляют дополнительные функции и изменяют поведение методов. Декораторы можно комбинировать в любом порядке, создавая различные конфигурации объекта.

class Car {
  constructor() {
    this.price = 1500;
    this.model = 'any Car you want';
  }

  getCarPrice() {
    return this.price;
  }

  getCarModel() {
    return this.model;
  }
}

class Honda extends Car {
  constructor() {
    super();
    this.price = 2500;
    this.model = 'Honda Accord 2020';
  }
}

// Декоратор для добавления автопилота
class AutoPilot {
  constructor(car) {
    this.car = car;
  }

  addAutoPilot() {
    this.car.autopilot = true;
  }

  getCarPrice() {
    return this.car.getCarPrice() + 5000;
  }

  getCarModel() {
    return this.car.getCarModel();
  }

  getCarDescription() {
    return `${this.car.getCarModel()} with autopilot`;
  }
}

// Декоратор для добавления спойлера
class Spoiler {
  constructor(car) {
    this.car = car;
  }

  addSpoiler() {
    this.car.spoiler = true;
  }

  getCarPrice() {
    return this.car.getCarPrice() + 1000;
  }

  getCarModel() {
    return this.car.getCarModel();
  }

  paintSpoiler(color = 'white') {
    this.car.spoilerColor = color;
    return this.car.spoilerColor;
  }

  getCarDescription() {
    return `${this.car.getCarModel()} with spoiler`;
  }
}

// Примеры использования
const basicHonda = new Honda();
console.log(basicHonda.getCarPrice()); // 2500

// Декорируем базовую Honda автопилотом
const hondaWithAutopilot = new AutoPilot(new Honda());
hondaWithAutopilot.addAutoPilot();
console.log(hondaWithAutopilot.getCarPrice()); // 7500
console.log(hondaWithAutopilot.getCarDescription()); // "Honda Accord 2020 with autopilot"

// Комбинируем декораторы: автопилот + спойлер
const hondaWithAutopilot2 = new AutoPilot(new Honda());
hondaWithAutopilot2.addAutoPilot();
const hondaWithAutopilotAndSpoiler = new Spoiler(hondaWithAutopilot2);
hondaWithAutopilotAndSpoiler.addSpoiler();
console.log(hondaWithAutopilotAndSpoiler.getCarPrice()); // 8500