Обзор шаблона проектирования Builder и его реализации в Dart и Flutter

Ранее в этой серии я проанализировал относительно сложный, но очень практичный и полезный шаблон структурного проектирования - Мост. На этот раз я хотел бы представить шаблон проектирования, который разделяет построение сложного объекта на несколько отдельных шагов. Это шаблон творческого проектирования под названием Builder.

Оглавление

  • Что такое шаблон проектирования Builder?
  • Анализ
  • Реализация
  • Другие статьи из этой серии
  • Ваш вклад

Что такое шаблон проектирования Builder?

Builder - это шаблон творческого проектирования, цель которого в книге GoF описана так:

Отделите построение сложного объекта от его представления, чтобы один и тот же процесс построения мог создавать разные представления.

Намерение можно разделить на две части:

Отделить построение сложного объекта от его представления…

Вы уже должны были заметить это в большинстве шаблонов проектирования, рассмотренных в этой серии, возможно, в несколько иной форме, например отделить абстракцию от ее представления. В этом случае одной из основных целей шаблона проектирования Builder является отделение процесса (логики) создания сложного объекта от самого объекта (данных). Что такое сложный объект? Что ж, нет конкретной точки или каких-либо критериев объекта, когда можно было бы сказать, что он сложный. Обычно объект может считаться сложным, когда создание объекта не заканчивается просто вызовом его конструктора - кроме того, вы должны установить некоторые дополнительные конкретные параметры, вызвать дополнительные методы.

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

… Так что один и тот же процесс построения может создавать разные представления.

Ах, вот в чем дело! Чтобы лучше понять это, допустим, мы строим дом. Чтобы построить дом (объект), этапы строительства (логика построения) в значительной степени одинаковы - вам нужен фундамент, пол, некоторые стены, двери, окна, крыша и т. Д. Несмотря на то, что процесс строительства дома является основным То же самое, каждый из этих шагов можно было отрегулировать, поэтому конечный результат выглядел бы совершенно иначе. И это основная идея шаблона проектирования Builder - абстрагироваться от процесса создания объекта, чтобы шаги построения можно было скорректировать, чтобы обеспечить другое представление (конечный результат).

Шаблон проектирования Builder перемещает код построения объекта из своего собственного класса в отдельные объекты, называемые конструкторами . Каждый из этих построителей следует одному и тому же интерфейсу и реализует отдельные этапы построения объекта. То есть, если вам нужно другое представление объекта, просто создайте другой класс builder и соответствующим образом выполните эти шаги построения. Кроме того, в шаблоне проектирования Builder есть еще один дополнительный слой - Director. Director - это простой класс, который знает об интерфейсе Builder и определяет порядок выполнения шагов построения. Этот класс не является обязательным, но он скрывает детали построения продукта от клиентского кода.

Я знаю, что структура шаблона проектирования Builder довольно сложна, поэтому давайте перейдем к частям анализа и реализации, чтобы лучше понять ее!

Анализ

Общая структура паттерна проектирования Builder выглядит так:

  • Builder - определяет абстрактный интерфейс, общий для всех типов построителей, для создания частей продукта;
  • Concrete Builder - обеспечивает конкретную реализацию этапов строительства. Кроме того, он определяет и отслеживает создаваемый Продукт;
  • Director - конструирует объект с помощью интерфейса Builder, определяет порядок, в котором вызываются шаги построения;
  • Продукт - представляет собой сложный объект в процессе строительства, предоставляет интерфейс / методы для сборки частей в конечный результат;
  • Клиент - связывает конкретный объект Builder с Director. Позже создается объект Product путем вызова экземпляра класса Director.

Применимость

Шаблон проектирования Builder следует использовать, когда вы заметили, что несколько конструкторов одного и того же класса ссылаются друг на друга. Например, у вас есть конструктор с несколькими необязательными параметрами. Некоторые из этих параметров имеют значения по умолчанию, поэтому вы создаете несколько более коротких конструкторов с меньшим количеством параметров, но по-прежнему ссылаетесь на основной. Используя шаблон проектирования Builder, вы строите объекты шаг за шагом, используя только те шаги, которые действительно необходимы - вам больше не нужно справляться с проблемой нескольких конструкторов с необязательными параметрами.

Как уже упоминалось, этот шаблон следует использовать, когда вы хотите создать разные представления какого-либо продукта. То есть узор может быть применен, когда этапы строительства схожи, но отличаются в деталях. Интерфейс построителя определяет эти шаги (некоторые из них могут даже иметь реализацию по умолчанию), в то время как конкретные разработчики реализуют эти шаги для создания определенного представления продукта.

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

Реализация

На этот раз часть реализации очень проста - мы будем использовать шаблон проектирования Builder для реализации процесса сборки гамбургеров McDonald’s.

Как вы, возможно, знаете, в меню McDonald’s есть несколько гамбургеров (обычный бургер, чизбургер, Биг Мак и многие другие). Во всех этих бургерах используются одни и те же продукты, только список ингредиентов отличается:

  • Обычный бургер - булочки, котлета из говядины, кетчуп, горчица, приправа для гриля, лук, соленые дольки;
  • Чизбургер - булочки, котлета из говядины, сыр, кетчуп, горчица, приправа для гриля, лук, соленые дольки;
  • Биг Мак - булочки, сыр, котлета из говядины, соус Биг Мак, приправа для гриля, лук, соленые дольки, тертый салат.

Как видите, изменяя процесс сборки бургера (меняя ингредиенты), мы полностью меняем конечный результат. Также в любой момент может появиться требование добавить в меню новый бургер. Наконец, должен быть реализован удобный пользовательский интерфейс, в котором вы можете выбрать бургер из меню и увидеть его цену, ингредиенты и список аллергенов.

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

Диаграмма классов

На диаграмме классов ниже показана реализация шаблона проектирования Builder:

Ingredient - это абстрактный класс, который используется в качестве базового класса для всех классов ингредиентов. Класс содержит свойства аллергены и name, а также методы getAllergens () и getName () для возврата значений. этих свойств.

Существует множество классов конкретных ингредиентов: BigMacBun, RegularBun, BeefPatty, McChickenPatty, BigMacSauce , кетчуп, майонез, горчица, лук, соленые ломтики, тертый салат, сыр и приправка для гриля. Все эти классы представляют определенный ингредиент бургера и содержат конструктор по умолчанию для установки значений свойств аллергены и name базового класса.

Burger - это простой класс, представляющий продукт строителя. Он содержит список ингредиентов и свойство price для хранения соответствующих значений. Также в классе есть несколько методов:

  • addIngredient () - добавляет ингредиент в бургер;
  • getFormattedIngredients () - возвращает отформатированный список ингредиентов бургера (через запятую);
  • getFormattedAllergens () - возвращает отформатированный список аллергенов бургера (через запятую);
  • getFormattedPrice () - возвращает форматированную цену бургера;
  • setPrice () - устанавливает цену бургера.

BurgerBuilderBase - это абстрактный класс, который используется в качестве базового класса для всех классов построителя бургеров. Он содержит свойства burger и price для хранения конечного продукта - бургера - и его цены соответственно. Кроме того, в классе хранятся некоторые методы с реализацией по умолчанию:

  • createBurger () - инициализирует объект класса Burger;
  • getBurger () - возвращает результат встроенного бургера;
  • setBurgerPrice () - устанавливает цену для объекта бургера.

BurgerBuilderBase также содержит несколько абстрактных методов, которые должны быть реализованы в определенных классах реализации конструктора бургеров: addBuns (), addCheese (), addPatties (), addSauces (), addSeasoning () и addVegetables ().

BigMacBuilder, CheeseburgerBuilder, HamburgerBuilder и McChickenBuilder - это классы конкретных построителей, которые расширяют абстрактный класс BurgerBuilderBase и реализовать его абстрактные методы.

BurgerMaker - это класс директора, который управляет процессом создания бургера. Он содержит конкретную реализацию построителя в виде свойства burgerBuilder, метода prepareBurger () для создания гамбургера и метода getBurger () для его возврата. Кроме того, реализацию построителя можно изменить с помощью метода changeBurgerBuilder ().

BuilderExample инициализирует и содержит класс BurgerMaker. Кроме того, он ссылается на все конкретные конструкторы бургеров, которые можно изменить во время выполнения с помощью раскрывающегося меню пользовательского интерфейса.

Ингредиент

Абстрактный класс, который хранит поля аллергены, name и расширяется всеми классами ингредиентов.

Бетонные ингредиенты

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

  • Биг Мак Булочка

  • Обычная булочка

  • Сыр

  • Приправа для гриля

  • Котлета из говядины

  • МакЧикен Пэтти

  • Соус Биг Мак

  • Кетчуп

  • Майонез

  • Горчица

  • Лук

  • Соленые ломтики

  • Тертый салат

Бургер

Простой класс для хранения информации о бургере: его цена и список ингредиентов, которые он содержит. Кроме того, методы класса, такие как getFormattedIngredients (), getFormattedAllergens () и getFormattedPrice (), возвращают эти значения в удобочитаемом формате.

BurgerBuilderBase

Абстрактный класс, в котором хранятся свойства burger и price, определяет некоторые методы по умолчанию для создания / возврата объекта burger и установки его цены. Кроме того, класс определяет несколько абстрактных методов, которые должны быть реализованы производными классами построителя бургеров.

Бетонные строители

  • BigMacBuilder - создает Big Mac из следующих ингредиентов: BigMacBun, Cheese, BeefPatty, BigMacSauce , Приправка для гриля, Лук, Ломтики маринованных огурцов и ShreddedLettuce.

  • CheeseburgerBuilder - создает чизбургер из следующих ингредиентов: RegularBun, Cheese, BeefPatty, Ketchup , Горчица, Приправка для гриля, Лук и Ломтики маринада.

  • HamburgerBuilder - создает чизбургер из следующих ингредиентов: RegularBun, BeefPatty, Кетчуп, Горчица , GrillSeasoning, Лук и PickleSlices. AddCheese () не имеет отношения к этому построителю, поэтому реализация не предоставляется (пропущена).

  • McChickenBuilder - создает чизбургер из следующих ингредиентов: RegularBun, McChickenPatty, Майонез и ShreddedLettuce . Методы AddCheese () и addSeasoning () не имеют отношения к этому построителю, поэтому реализация не предоставляется (пропущена).

БургерМейкер

Класс директора, который управляет процессом сборки бургера и возвращает результат сборки. Конкретная реализация построителя вводится в класс через конструктор.

Пример

Прежде всего, подготавливается файл разметки, который предоставляется как описание шаблона:

BuilderExample инициализирует и содержит объект класса BurgerMaker. Кроме того, он содержит список объектов / элементов выбора BurgerMenuItem, который используется для выбора конкретного построителя с помощью пользовательского интерфейса.

Класс директора BurgerMaker не заботится о конкретной реализации построителя - конкретная реализация может быть изменена во время выполнения, что дает другой результат. Кроме того, такая реализация позволяет легко добавить новый конструктор (при условии, что он расширяет класс BurgerBuilderBase), чтобы обеспечить представление другого продукта без нарушения существующего кода.

Как вы можете видеть в примере, когда конкретный конструктор выбирается из раскрывающегося списка, создается новый продукт (бургер), и информация о нем предоставляется в пользовательском интерфейсе - цена, ингредиенты и аллергены.

Все изменения кода для шаблона проектирования Builder и его пример реализации можно найти здесь.

Другие статьи из этой серии

Ваш вклад

👏 Нажмите кнопку хлопка ниже, чтобы выразить свою поддержку и побудить меня писать лучше!
💬 Оставьте отзыв на эту статью, поделившись своими мыслями, комментариями или пожеланиями относительно серии.
📢 Поделитесь этой статьей со своими друзья, коллеги в социальных сетях.
➕ Подписывайтесь на меня на Medium.
⭐ Пометьте репозиторий Github.