What is builder in android

Java. Шаблон Builder

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

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

Создадим для примера «плохой» класс с двумя обязательными и с четырьмя необязательными параметрами.

Создание экземпляра класса с использованием конструктора со всем набором параметров.

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

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

Количество кода в классе увеличивается, но код стал более читаемым при создании экземпляра класса.

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

Поэтому был придуман третий вариант, который назвали шаблоном Builder. Вместо непосредственного создания объекта класса вызывается конструктор (или статический метод) со всеми необходимыми параметрами, чтобы получить объект Builder. Затем вызываются сеттеры для установки всех необходимых параметров. В завершение, вызывается метод build() для генерации объекта, который будет являться неизменным. Реализуется такой подход через статический внутренний класс.

Создадим уже «хороший» класс с применением Builder.

Класс GoodClass является неизменным и все значения параметров по умолчанию находятся в одном месте. Сеттеры возвращают класс-строитель, поэтому вызовы можно объявлять в цепочку.

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

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

Создавайте Builder в том случае, когда параметров четыре и больше. В остальных случаях используйте традиционный подход.

Источник

Kotlin и “строитель” (он же Builder)

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

Давайте сразу окунемся в пучину кода. Рассмотрим вот такой пример.

В качестве сеттера для свойства nickname мы написали функцию, которая применяет параметр к нашему свойству. Все довольно просто, но после Java не так очевидно.

Однако (!) скажете вы, часто же строитель используется немного по другой схеме. Скажем, строитель может быть для кастомного аккаунта, а может быть для создания диалогового окна. Ты же помнишь, как это описывается по старинке, ну типа AlertDialog.Builder() и так далее?

Если так скажете, отвечу — прям с языка сорвали продолжение истории. Смотрим пример номер два — аккаунт и билдер (мне как-то это привычнее, чем строитель, если честно)

Что мы тут имеем. Объект Account, который создается с помощью билдера и никак иначе (дефолтный конструктор использует параметр только нашего типа). В билдере все как обычно — есть поля, есть сеттеры в которых— о, чудо! — мы избавились от одной лишней строки (я имею в виду return this, как раньше).

Создание нашего объекта выглядет прелестно (я сюда же добавил пару распечаток, ну так, для наглядности вызова)

Источник

Паттерн проектирования Builder (Строитель) в Java

Приглашаем также всех желающих на открытый демо-урок «Шаблоны GRASP». На этом занятии мы проанализируем функциональное разделение функционала и рассмотрим 9 шаблонов GRASP. Присоединяйтесь!

А вот и я со своей очередной статьей о паттернах проектирования, а именно о паттерне проектирования Builder (он же Строитель). Очень полезный паттерн проектирования, который позволяет нам шаг за шагом конструировать сложные объекты.

Читайте также:  Черные смайлики для андроид

Паттерн проектирования Builder

Паттерн проектирования Builder разработан для обеспечения гибкого решения различных задач создания объектов в объектно-ориентированном программировании.

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

Паттерн Builder создает сложные объекты, используя простые объекты и поэтапный подход.

Паттерн предоставляет один из лучших способов создания сложных объектов.

Это один из паттернов проектирования банды четырех (GoF), которые описывают, как решать периодически возникающие задачи проектирования в объектно-ориентированном программном обеспечении.

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

Паттерн Builder — это паттерн проектирования, который позволяет поэтапно создавать сложные объекты с помощью четко определенной последовательности действий. Строительство контролируется объектом-распорядителем (director), которому нужно знать только тип создаваемого объекта.

Итак, паттерн проектирования Builder можно разбить на следующие важные компоненты:

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

Builder (строитель) — абстрактный класс/интерфейс, который определяет все этапы, необходимые для производства сложного объекта-продукта. Как правило, здесь объявляются (абстрактно) все этапы (buildPart), а их реализация относится к классам конкретных строителей (ConcreteBuilder).

ConcreteBuilder (конкретный строитель) — класс-строитель, который предоставляет фактический код для создания объекта-продукта. У нас может быть несколько разных ConcreteBuilder-классов, каждый из которых реализует различную разновидность или способ создания объекта-продукта.

Director (распорядитель) — супервизионный класс, под конролем котрого строитель выполняет скоординированные этапы для создания объекта-продукта. Распорядитель обычно получает на вход строителя с этапами на выполнение в четком порядке для построения объекта-продукта.

Паттерн проектирования Builder решает такие проблемы, как:

Как класс (тот же самый процесс строительства) может создавать различные представления сложного объекта?

Как можно упростить класс, занимающийся созданием сложного объекта?

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

Пример со сборкой автомобилей с использованием паттерна проектирования Builder

Шаг 1: Создайте класс Car (автомобиль), который в нашем примере является продуктом:

Обратите внимание, что я добавил в класс проверочный метод doQualityCheck . Я считаю, что Builder не должен создавать неполные или невалидные Product-объекты. Таким образом, этот метод поможет нам в проверке сборки автомобилей.

Шаг 2: Создайте абстрактный класс/интерфейс CarBuilder , в котором определите все необходимые шаги для создания автомобиля.

Обратите внимание, что я сделал тип CarBuilder типом возврата всех этапов, созданных здесь. Это позволит нам вызывать этапы по цепочке. Здесь есть один очень важный метод build , который заключается в том, чтобы получить результат или создать конечный объект Car . Этот метод фактически проверяет годность автомобиля и выпускает (возвращает) его только в том случае, если его сборка завершена успешно (все валидно).

Шаг 3: Теперь пора написать ConcreteBuilder . Как я уже упоминал, у нас могут быть разные варианты ConcreteBuilder , и каждый из них выполняет сборку по-своему, чтобы предоставить нам различные представления сложного объекта Car .

Итак, ниже приведен код ClassicCarBuilder , который собирает старые модели автомобилей.

Теперь напишем еще один строитель ModernCarBuilder для сборки последней модели автомобиля.

И еще один SportsCarBuilder для создания спортивного автомобиля.

Шаг 4: Теперь мы напишем класс-распорядитель AutomotiveEngineer , под руководством которого строитель будет собирать автомобиль (объект Car ) шаг за шагом в четко определенном порядке.

Мы видим, что метод manufactureCar вызывает этапы сборки автомобиля в правильном порядке.

Теперь пришло время написать класс Main для выполнения и тестирования нашего кода.

Ниже приведен вывод программы:

Я надеюсь, что вы хорошо разобрались в объяснении и примере, чтобы понять паттерн Builder . Некоторые из нас также находят у него сходство с паттерном абстрактной фабрики (Abstract Factory), о котором я рассказывал в другой статье. Основное различие между строителем и абстрактной фабрикой состоит в том, что строитель предоставляет нам больший или лучший контроль над процессом создания объекта. Если вкратце, то паттерн абстрактной фабрики отвечает на вопрос «что», а паттерн строитель — «как».

Я нашел паттерн Builder невероятно полезным и одним из наиболее часто используемых в приложениях в настоящее время. Я пришел к выводу, что Builder лучше подходит для работы с иммутабельными объектами. Все мы знаем, как много есть хороших иммутабельных объектов, и их использование увеличивается день ото дня, особенно после релиза Java 8.

Читайте также:  Невозможно открыть изображение андроид

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

В качестве примера у нас есть класс Employee , в котором есть несколько полей.

Предположим, только два поля EmpNo и EmpName являются обязательными, а все остальные — опциональные. Поскольку это иммутабельный класс, у меня есть два варианта написания конструкторов.

Написать конструктор с параметрами под все поля.

Написать несколько конструкторов для разных комбинаций параметров, чтобы создать разные представления объекта Employee .

Я решил, что первый вариант мне не подходит, так как мне не нравится, когда в методе больше трех-четырех параметров. Это выглядит не очень хорошо и становится еще хуже, когда многие параметры равны нулю или null .

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

Итак, вот решение с помощью паттерна Builder :

Я написал EmployeeBuilder как публичный статический вложенный класс. Вы можете написать его как обычный публичный класс в отдельном файл Java. Большой разницы я не вижу.

Теперь напишем программу EmployeeMain для создания объекта Employee :

Надеюсь, вам понравилась идея. Мы можем использовать это при создании более сложных объектов. Я не реализовал здесь распорядителя (Director), так как все шаги (сбор значений для полей) не являются обязательными и могут выполняться в любом порядке. Чтобы убедиться, что я создаю объект Employee только после получения всех обязательных полей, я написал метод проверки.

Пример с оформлением заказа в ресторане с использованием паттерна Builder

Я хочу еще показать вам пример кода для оформления заказа в ресторане, где Order (заказ) является иммутабельным объектом и требует тип обслуживания заказа — Order Service Type (Take Away — с собой/Eat Here — в заведении), всех необходимых нам продуктов питания (Food Items) и имени клиента (Customer Name — опционально) в время оформления заказа. Продуктов питания может быть сколько угодно. Итак, вот код этого примера.

Код для перечисления OrderService :

Код для интерфейса FoodItem :

Код для класса Meal (блюдо). Класс Meal предлагает заранее определенные продукты питания со скидкой на цену товара (не на цену упаковки).

Код для класса Burger :

Код для класса ChickenBurger :

Код для класса VegBurger (веганский бургер):

Код для класса Nuggets :

Код для класса CheeseNuggets :

Код для класса ChickenNuggets :

Напитки:

Напитки бывают разных размеров. Итак, вот код перечисления BeverageSize :

Код для класса Drink :

Код для класса ColdDrink :

Код для класса CocaCola :

Код для класса Pepsi :

Код для класса HotDrink :

Код для класса Cuppuccinno :

Код для класса HotChocolate :

Упаковка:

Код интерфейса Packing :

Код для класса Bottle :

Код для класса Container :

Код для класса MultiPack . Упаковка MutiPack служит вспомогательной упаковкой для еды, когда мы используем разные упаковки для разных продуктов.

Код для класса SipperMug :

Код для класса Wrap :

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

Почти все готово. Пришло время написать наш иммутабельный класс Order :

А вот код для OrderBuilder , который конструирует объект Order .

Готово! Теперь пришло время написать Main для выполнения и тестирования результат:

А вот и результат работы программы:

Ну вот и все! Я надеюсь, что этот урок помог освоить паттерн Builder.

Источник

Эволюция паттерна Builder в Android.

Продолжаем тему паттернов проектирования. На этот раз рассмотрим порождающий шаблон проектирования Builder. Мы рассмотрим какую проблему решает Builder в Java, какие у него есть “братья” и как этот паттерн эволюционировал в Android-разработке при использовании Kotlin.

Проблема

В первую очередь хочется поговорить, о проблеме, которую призван решить Builder. Чаще всего Строитель (он же Builder) используется для пошаговой инициализации множества полей и вложенных объектов. Код инициализации таких объектов чаще всего спрятан внутри монструозного конструктора с десятком параметров. Либо ещё хуже — распылён по всему клиентскому коду. Перед тем как перейти непосредственно к самому паттерну — давайте рассмотрим его “младших братьев” которые могут теоретически помочь при решении описанной выше проблемы.

Так себе решение #1. Телескопический конструктор

Традиционно, программисты использовали Telescoping Constructor паттерн. Суть этого паттерна состоит в том, что Вы предоставляете несколько конструкторов: конструктор с обязательными параметрами, конструктор с одним дополнительным параметром, конструктор с двумя дополнительными параметрами, и так далее. Продемонстрируем как это будет выглядеть на практике. Для краткости будем использовать только 4 дополнительных параметра.

Читайте также:  Morelocale 2 для андроид

Таким образом, когда Вы хотите создать объект данного класса, Вы используете конструктор с необходимым списком параметров:

Обычно для вызова конструктора потребуется передавать множество параметров, которые Вы не хотите устанавливать, но Вы в любом случае вынуждены передать для них значение. В нашем случае, мы установили значение 0 для поля fat . Поскольку мы имеем только шесть параметров, может показаться, что это не так уж и плохо. Но это начинает доставлять огромные проблемы когда число параметров увеличивается.

Минусы такого подхода:

Когда имеется много параметров становится сложно создавать объект, а еще труднее этот код читать. Остается только гадать, что означают все эти значения.

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

Так себе решение #2. JavaBeans паттерн

Видели множество set()-методов для создания сложного объекта? Думаю все видели размазанные по всему коду сетеры — которые оставляют неконсистентное состояние при инициализации объекта:

Вы вызываете конструктор без параметров, чтобы создать объект, а затем вызываете сеттеры для установки обязательных и дополнительных параметров, представляющих интерес. Однако, такой подход является антипаттерном:

“The JavaBeans pattern has serious disadvantages.” — Joshua Bloch, Effective Java

Минусы такого подхода:

Поскольку строительство разделено между несколькими вызовами, JavaBean может находиться в неустойчивом состоянии частично пройдя через конструирование. Попытка использования объекта, если он находится в неустойчивом состоянии может привести к ошибкам, которые далеки от кода, содержащего ошибку, следовательно, трудными для отладки. Также JavaBeans паттерн исключает возможность сделать класс неизменным(immutable), что требует дополнительных усилий со стороны программиста для обеспечения безопасности в многопоточной среде.

Хорошее решение #3. Паттерн Builder

Третья альтернатива, сочетающая в себе безопасность паттерна Telescoping Constructor с читаемостью паттерна JavaBeans — это паттерн Builder.

Вместо непосредственного создания желаемого объекта, клиент вызывает конструктор (или статическую фабрику) со всеми необходимыми параметрами и получает объект строителя. Затем клиент вызывает сеттер-подобные методы у объекта строителя для установки каждого дополнительного параметра. Наконец, клиент вызывает метод build() для генерации объекта, который будет являться неизменным(immutable). Строитель является статическим внутренним классом в классе, который он строит. Вот как это выглядит на практике:

Ну и теперь конструирование объекта сводится к вызову необходимых методов:

Преимущества паттерна:

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

Хорошее решение #4. Паттерн Builder в Kotlin

На дворе 2021 год, и программирование под Android развивается семимильными шагами. И если раньше подход №3 считался стандартом, то встаёт вопрос: “А надо ли реализовывать паттерн Builder в Kotlin?” Перед тем, как ответить на данный вопрос, давайте вспомним цели, которые мы хотели достичь, используя Builder:

  • Конструирование сложного объекта с большим количеством аргументов (возможно с одинаковым типом)
  • Возможность создания разных объектов с разным количеством аргументов (часть из аргументов может быть опциональными)
  • Неизменяемость построенного объекта

Теперь, давайте пройдёмся по каждому пункту и посмотрим, что нам может предложить Kotlin.

В Koltin есть 2 крутые фичи: именованныt аргументы и дефолтные аргументы. Таким образом, мы убиваем 2-ух зайцев сразу. Во-первых, используя именнованные аргументы, мы теперь можем передавать в конструктор 100500 различных аргументов и при этом они могут быть одного типа — перепутать их будет достаточно сложно. А использование дефолтных значений для аргументов — избавляет нас постоянно описывать ненужные значения — как это было в подходе с телескопическим конструктором. Ну а неизменяемость построенного объекта очень легко достичь, объявив поля класса через val.

Сконструировать такой объект теперь мы можем так:

Таким образом, Kotlin очень сильно упростил нам задачу. И теперь паттерн Builder является частью языка, и нет необходимости конвертировать его Java-реализацию. Достаточно придерживаться описанных выше правил.

Надеюсь, в этой статье вы уловили суть паттерна Builder, а также теперь знаете врагов в лице парочки антипаттернов и сможете писать более читабельный и эффективный код на Kotlin. Ну а если вы хотите прокачаться в Android-разработке, то приглашаю вас на 3-ий поток интенсива по Android-разработке на Kotlin. До 25 января скидка 15%. Узнать подробности можно по ссылке.

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

Понравилась статья? Не забудь подписаться и поставить лайк, а ещё

Источник

Оцените статью