Mediator Pattern

Паттерн Посредник для уменьшения взаимосвязей между классами

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

В примере ниже класс Intermediary выступает посредником между Customer и Government. Клиенты делают заказы через посредника, который регистрирует их и хранит информацию. Правительство получает данные о налогах также через посредника, не взаимодействуя напрямую с клиентами. Это позволяет легко добавлять новую логику (например, уведомления, валидацию) без изменения классов клиентов.

// Класс клиента
class Customer {
  constructor(name, mediator) {
    this.name = name;
    this.mediator = mediator;
  }

  getName() {
    return this.name;
  }

  orderProduct(options) {
    // Делегируем обработку заказа посреднику
    this.mediator.order(this, options);
  }
}

// Класс правительства
class Government {
  constructor(name, mediator) {
    this.name = name;
    this.mediator = mediator;
  }

  getTax() {
    // Получаем данные о ценах через посредника
    const prices = this.mediator.customersPrices.map((price) =>
      parseFloat(price.replace('$', ''))
    );
    const total = prices.reduce((acc, curr) => acc + curr * 0.13, 0);
    console.log(`Customers paid $${total.toFixed(2)} in taxes`);
    return total;
  }
}

// Посредник - скрывает все связи между классами
class Intermediary {
  constructor() {
    this.customers = [];
    this.customersPrices = [];
  }

  addCustomer(name) {
    this.customers.push(name);
  }

  addPrice(price) {
    this.customersPrices.push(price);
  }

  order(currentCustomer, options) {
    const name = currentCustomer.getName();
    const { price, country, year, type } = options;

    console.log(`${name} created order to buy ${type} with price ${price}`);
    console.log(`Desired country and year of product: ${country}/${year}`);

    // Регистрируем заказ
    this.addCustomer(name);
    this.addPrice(price);
  }

  getCustomers() {
    return this.customers;
  }

  getTotalOrders() {
    return this.customers.length;
  }
}

// Примеры использования
const intermediary = new Intermediary();

const kirill = new Customer('Kirill', intermediary);
const sophia = new Customer('Sophia', intermediary);
const gov = new Government('Russia', intermediary);

// Клиенты делают заказы через посредника
kirill.orderProduct({
  type: 'iPhone 14',
  country: 'Dubai',
  year: 2022,
  price: '1000$'
});

sophia.orderProduct({
  type: 'Macbook',
  country: 'Germany',
  year: 2020,
  price: '1200$'
});

// Правительство получает данные о налогах через посредника
gov.getTax(); // "Customers paid $286.00 in taxes"

// Посредник предоставляет дополнительную информацию
console.log(`Total orders: ${intermediary.getTotalOrders()}`); // "Total orders: 2"
console.log(`Customers: ${intermediary.getCustomers().join(', ')}`); // "Customers: Kirill, Sophia"