Как решить шаблонную проблему шаблона Builder

kak reshit shablonnuyu problemu shablona builder?v=1656619574

от Harshdeep S Jawanda

0*pWJ2kCkdoFaXrlK6
Фото Саи Кирана Анагани на Unsplash

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

Введение в шаблон конструктора

Шаблон конструктора отлично подходит для классов, которые могут иметь сложную инициализацию. Обычно он состоит из установления значений для нескольких переменных, некоторые из которых могут быть обязательными, а другие необязательными. Использование статических фабричных методов или конструкторов может привести к узор телескопического конструктораописан Джошуа Блоком («Эффективный автор Java, дизайнер API, Swell guy», как говорит его Twitter) так:

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

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

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

Кроме всех этих радужных преимуществ, на самом деле написание конструктора может быть достаточно изнурительной и повторяющейся задачей. «И что!?» вы говорите: «По крайней мере, я получаю все эти преимущества!» Конечно, что так… но вернись и поговори со мной, когда будешь писать десятый строитель по тому же проекту.

Давайте рассмотрим некоторые другие варианты.

Делаем это динамично: Ломбок

Lombok – это инструмент/библиотека, хорошо известная многим разработчикам Java (хотя недостаточно, ИМХО). Согласно его веб-сайту, это «библиотека Java, которая автоматически подключается к вашему редактору и создает инструменты, оживляя вашу Java». Lombok добавляет так много функций благодаря динамической генерации кода, что их просто невозможно рассмотреть здесь. Мы сосредоточимся на @Builder абстрактный.

The @Builder аннотацию – как следует из названия – можно использовать для создания конструктора для любого POJO. Его можно использовать, поместив его в класс, конструктор или статический метод (подробнее смотрите в документации). Просто разместите аннотацию на Person класс:

И по магии Ломбока, а PersonBuilder класс автоматически создается мгновенно. Теперь мы можем создать экземпляр a Person объект с помощью шаблона конструктора:

Person.builder().firstName("Adam").lastName("Savage")    .city("San Francisco").jobTitle("TV Personality").build();

Размещение @Builder аннотация на Person класс

  1. создает а PersonBuilder класс со свободными сеттерами для всех свойств Person класс и а build() метод построения а Person объект с использованием набора значений, и,
  2. добавляет а public static builder() метод к Person класс, возвращающий новый экземпляр PersonBuilder.

Размещение @Builder аннотация конструктора или статического метода выполняет то же, что и выше, но генерирует сеттеры только для параметров, перечисленных в методе конструктора/статического.

Добавление @NonNull аннотация к полю Person класс делает это a требуется параметр. Не устанавливает его значение с помощью PersonBuilderсоответствующий метод установки бросит a NullPointerException когда build() метод называется.

Прелесть Lombok заключается в том, что ни один из сгенерированного кода не отображается в исходном файле (хотя Eclipse покажет сгенерированные классы, методы и поля в представлении Outline), оставляя его очень чистым и аккуратным. Разработчику нужно сосредоточиться только на важных частях POJO, а не на скучных деталях его (часто) повседневной реализации. Внесите любые изменения в POJO и Lombok немедленно обновит/генерирует соответствующий код.

Недостатки Ломбока

Несмотря на всю эту магическую доброту, Ломбок не идеален.

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

Ранее назначать значение по умолчанию полям POJO было очень скучно:

  1. Напишите скелет класса конструктора с правильным названием.
  2. Напишите соответствующее/правильно указанное поле и установите значение по умолчанию.

Однако назначать значение по умолчанию стало проще с версии 1.16.16 Lombok с помощью @Builder.Default аннотация:

Еще одним недостатком – хотя не все с этим согласятся – является то, что проверка нулевого значения (или a требуется значение имеет установлено) и бросание NPE выполнено в конструкторе с POJO, нет раньше создание POJO. Я предпочитаю вообще не создавать POJO, если его предпосылки не удовлетворяются.

Более общей проблемой с Lombok является то, что он плохо работает с инструментами рефакторинга IDE. Рассмотрим следующий (правда, глупый) код:

Если бы мы переименовали Person класс до HumanBeingимя соответствующего конструктора станет HumanBeingBuilder. Но инструменты рефакторинга IDE не смогут обновиться PersonBuilder выше до HumanBeingBuilder (по крайней мере, в Eclipse 🙂 ).

Однако существует простой способ решения этой проблемы: просто воспользуйтесь файлом Builder аннотации builderClassName возможность установить фиксированное название для класса конструктора: @Builder(builderClassName = "Builder") . Тогда все ссылки на класс конструктора станут Person.Builderкоторый будет правильно изменен путем рефакторинга до HumanBeing.Builder.

Делаем это статически: Eclipse Spark Plugin

Плагин Eclipse Spark позволяет генерировать код конструктора POJO, нажав одну кнопку на панели инструментов: это так просто! При нажатии на кнопку (необязательно) отобразится список полей, которые можно выбрать для использования в конструкторе. Код генерируется прямо на глазах и читается в файле.

Создание конструктора с помощью плагина Spark производит Person класс выглядит так:

Теперь, когда весь сгенерированный код находится прямо перед вами, вы можете настроить его (или нет!) по своему усмотрению. Но это даже не самая лучшая часть истории Spark.

Spark также позволяет создавать поэтапные конструкторы: глаза загораются от радости, когда вы впервые используете поэтапный конструктор, а ваша IDE предлагает именно правильные предложения автозаполнения! Объяснение поэтапных конструкторов выходит за рамки этой статьи, поэтому прочтите статью по ссылке выше, чтобы узнать больше.

Ни один из упомянутых выше недостатков Lombok не касается плагина Spark.

Недостатки Spark Plugin

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

Другая проблема состоит в том, что Spark – это пони с одним трюком: генерировать строителей – это все, что он может сделать – сравните это со всем, что может сделать Lombok.

Так что это?

Инструмент, который вы должны использовать, зависит от вашей уникальной ситуации и ваших предпочтений. Я буду продолжать отдавать предпочтение Lombok в подавляющем большинстве случаев, переходя на Spark всякий раз, когда мне нужен тонкий контроль.

Какую бы вы выбрали?

Последнее, но не самое важное…

Если эта статья была вам полезна, не забудьте аплодировать ;-)!

Конструктивные дискуссии и исправления приветствуются.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *