Что лучше — Fluent API или Builder?



Продолжим разговор о Fluent API и рассмотрим частный случай — создание объекта. Сравним "классический" флуент апи с билдером и посмотрим, когда что использовать.



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



Уточним термины



▫️ Fluent API — это стиль написания кода. Грубо говоря, когда методы соединяются через точку (method chaining). С помощью Fluent API можно создать объект и проинициализировать поля.



▫️ Builder — паттерн для создания объектов, суть которого в постепенном накоплении информации. Билдер тоже использует method chaining и относится к fluent api.



В чём разница на практике?



Допустим, надо создать экземпляр класса Account с информацией о счёте. Рассмотрим 4 варианта:



1️⃣ Все параметры передаём в конструкторе:

Account acc = new Account(111, 222, 333);


Идеально для обязательных параметров. Компилятор не даст шанса пользователю что-то забыть

Плохая читаемость — передаётся набор чисел, непонятно, что есть что

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



2️⃣ Параметры выставляем через сеттеры:

Account acc = new Account();

acc.setINN(111);

acc.setKPP(222);

acc.setRCBIC(333);


Читаемость лучше. Понятно, с какими полями работаем

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



3️⃣ Используем Fluent API:

Account acc = Account.new()

.INN(111)

.KPP(222)

.RCBIC(333);


Симпатичнее, чем сеттеры

Та же проблема с обязательными параметрами, никаких проверок

Не подходит для неизменяемых классов

Более сложный код. Но если у вас разрешён ломбок, аннотация @Accessors(chain = true) упрощает задачу



4️⃣ Создание объекта через билдер:

Account acc = Account.builder().

.INN(111)

.KPP(222)

.RCBIC(333)

.build();


В build() можно добавить нужные проверки

Можно использовать для неизменяемых классов

Надо написать отдельный класс Builder или использовать аннотацию @Builder из ломбока



Создание объекта через Fluent API не очень отличается от билдера по лаконичности, но проигрывает ему в функциональности. Fluent API не может проверить поля на "обязательность".



Итого



🔸 Если в классе мало полей, идём по классическому пути — обязательные параметры помещаем в конструктор, необязательные выставляем сеттерами

🔸 Если полей много или между полями сложные связи — используем билдер. Именованые методы улучшат читаемость, а метод build() проверит всё, что нужно



Fluent API обычно не даёт преимуществ в ситуациях выше, и редко используется для создания объектов. Его сильная сторона — логические блоки из нескольких операций🔥