Строитель — это один из Порождающих шаблонов, который помогает вам разобраться в том, как создаются объекты. Вам следует уделять пристальное внимание методам создания объектов, которые могут вылиться в серьезные проблемы дизайна, если вы ими пренебрегаете.

Начните здесь, если вы новичок в шаблонах проектирования в JavaScript

Примеры из реальной жизни

Представьте, что вам нужно собрать из крошечных деталей лего нечто, похожее на дом. Есть несколько разных способов сгруппировать их в различные представления.

Базовый дом будет иметь дверь, ноль или более окон и крышу с окружающими стенами. Некоторые могут даже иметь гараж, а некоторые — бассейн. Мы хотели бы, чтобы процесс был более простым и гибким, чтобы можно было вносить изменения.

Пошаговая сборка деталей лего, имеющихся в вашем распоряжении, составляет суть паттерна Строитель.

Таким образом, объекты конструируются в соответствии с последовательностью шагов один за другим, а не достигаются сразу.

Объекты JavaScript - это набор свойств и методов. Свойства - это поля или переменные, связанные с объектом. А методы — это функции, которые вы собираетесь вызывать для управления полями. Свойства объектов тесно связаны друг с другом, по крайней мере, в худшем случае семантически.

JavaScript предоставляет множество способов создания объектов.

Инициализатор объекта

Самый распространенный метод создания объекта в JavaScript - это нотация «объектный литерал».

const employee = {
  firstName: 'Sam',
  lastName: 'Greene',
  id: '12340987',
  phone: '07123456789'
};

где firstName, lastName, id и phone - это свойства объекта с именем employee.

Конструктор

В качестве альтернативы мы можем использовать конструктор для создания нескольких экземпляров похожих объектов с помощью ключевого слова new.

class Employee {
    constructor(fname, lname, id, ph) {
        this.firstName = fname;
        this.lastName = lname;
        this.id = id;
        this.ph;
    }
};

const employee1 = new Employee('Sam', 'Greene', 12340987, '07123456789');
const employee2 = new Employee('Nate', 'Tyson', 56478390, '07987654321');

Использование Object.create

Object.create() - это встроенная функция, которую вы можете использовать для создания нескольких экземпляров объекта. Это позволяет вам передать объект шаблона в качестве входных данных, таким образом, выбирая прототип для объектов по желанию, без конструктора.

const Employee = {
  isAdmin: false,
  getRole: function() {
	  return this.isAdmin ? 'Admin' : 'RegularEmp';
  };
};

const emp1 = Object.create(Employee);
emp1.getRole(); //'RegularEmp'

const emp2 = Object.create(Employee);
emp2.isAdmin = true;
emp2.getRole(); //'Admin'

В этом примере и emp1, и emp2 унаследовали метод getRole. Как только вы установите для параметра isAdmin значение true, роль emp2 изменится на Admin.

Эта проблема

Похоже, что уже существует несколько способов создания объектов в JavaScript. Зачем нам изобретать что-то другое?

Рассмотрим два важных вопроса:

  • Что делать, если вам нужно создать сложный объект, содержащий слишком много полей и свойств?
  • Что, если вам нужно создать несколько экземпляров почти одного и того же объекта?

Литерал объекта - не лучший выбор, поскольку он не помогает повторно использовать код. Каждый раз, когда вам нужен новый объект, вам придется снова и снова перечислять все его поля.

Конструктор до некоторой степени решил бы проблему, но это было бы громоздко. Вам нужно будет запомнить входные данные для него, некоторые из которых являются обязательными, а другие нет.

Паттерн Строитель

Что, если бы у вас был способ решить только две вышеупомянутые проблемы, скрывая внутреннее представление от всех, кто его использует?

В реальной жизни объекты окружают нас повсюду. И вы можете сравнивать с ними объекты JavaScript.

Например, автомобиль бывает разного цвета или с разным количеством сидений. В доме может быть разное количество дверей, окон и дымоходов. Различия есть везде, но есть некоторые сходства.

Шаблон Builder позволяет упростить создание сложного объекта, отделив его от его представления.

Этот шаблон упрощает создание объекта, выполняя процесс поэтапно, а также инкапсулируя (скрывая) детали реализации этих шагов.

Давайте посмотрим, как выглядит гибкий дизайн для простого конструктора OTG и как он развивается с помощью паттерна Builder.

Создание OTG с использованием шаблона проектирования Builder

Должна быть предусмотрена возможность создания OTG различных цветов, моделей, цен и функций. Некоторые из них рассчитаны на высокую температуру и имеют хороший интервал выбора таймера. Например, младшие модели идут с низкотемпературными настройками и таймером по умолчанию.

Шаг 1. Класс OTG

Простой класс для OTG здесь имеет конструктор JS, который принимает четыре параметра. У каждого экземпляра OTG есть заголовок по умолчанию, переопределяемая температура и выбор времени, которые по умолчанию установлены на 150 и 30 соответственно.

class OTG {
	constructor(model, color, maxTemperature, maxTimeSelection) {
	  this.model = model;
	  this.title = 'OTG';
	  this.color = color;
	  this.maxTemperature = maxTemperature || 150;
	  this.maxTimeSelection = maxTimeSelection || 30;
	}
}

const redOTG = new OTG('LG', 'red');
const highTempOTG = new OTG('LG', 'black', 200);
const highendTimeOTG = new OTG('LG', 'red', '150', '60');

Приведенный выше код пока выглядит нормально. Но с этим есть проблема.

Представьте, что вам нужно создать несколько выборок экземпляров OTG. Будет сложно отслеживать параметры и их порядок в конструкторе. Кроме того, иногда нет необходимости отправлять определенные необязательные параметры.

Шаг 2. Создайте класс строителя

Давайте посмотрим, как можно избежать забивания конструктора минимальными параметрами.

class OTGBuilder {
  constructor(model, color) {
    this.model = model;
    this.title = 'OTG';
    this.color = color;
  }
}

Здесь класс OTGBuilder отвечает за создание экземпляров класса OTG. Но пока этого не происходит. На данный момент он просто захватывает базовую модель и цвет полей.

Эти поля являются обязательными, поэтому мы включаем их прямо в конструктор.

Шаг 3. Добавьте необязательные параметры как отдельные функции

Вы, наверное, заметили, что поля maxTemperature и maxTimeSelection нельзя настроить с помощью конструктора.

Эти свойства необязательны, и мы создадим отдельные функции для их установки.

class OTGBuilder {
  constructor(model, color) {
	  this.model = model;
    this.title = 'OTG';
    this.color = color;
  }
  setMaxTemperature(temp) {
    this.maxTemperature = temp;
    return this;
  }

  setMaxTimeSelection(maxTime) {
    this.maxTimeSelection = maxTime;
    return this;
  }
}

Необходимо добавить return this;, чтобы убедиться, что мы можем использовать цепной вызов при работе с шаблоном проектирования Builder.

const otg = new OTGBuilder('MorphyRichards', 'Black')
.setMaxTemperature(250)
.setMaxTimeSelection(60);

Шаг 4. Сборка

Единственная оставшаяся проблема заключается в том, что объект otg еще не является подходящим OTG. Это экземпляр класса OTGBuilder. И вам нужно реализовать последний шаг процесса — метод build ().

class OTGBuilder {
  constructor(model, color) {
    this.model = model;
    this.title = 'OTG';
    this.color = color;
  }
  setMaxTemperature(temp) {
    this.maxTemperature = temp;
    return this;
  }

  setMaxTimeSelection(maxTime) {
    this.maxTimeSelection = maxTime;
    return this;
  }

  build() {
    return new OTG(this.model, this.color,
    this.maxTemperature, this.maxTimeSelection);
  }
}

Теперь вы можете вызвать метод build(), когда будете готовы создать свой OTG.

const basicOTG = new OTGBuilder('MorphyRichards', 'Black')
  .setMaxTemperature(250)
  .setMaxTimeSelection(60)
  .build();

При желании вы всегда можете пропустить шаги по установке дополнительных параметров.

const default = new OTGBuilder('Generic OTG', 'White')
  .build();

Для свойств maxTemperature и maxTimeSelection по умолчанию будут заданы значения 150 и 30, если вы не перезапишете их с помощью setMaxTemperature и setMaxTimeSelection.

Получите мою бесплатную электронную книгу, чтобы подготовиться к техническому собеседованию, или начните учить Full-Stack JavaScript