Шаблон Builder с плавным API
Создавайте сложные объекты пошагово с помощью плавного строителя, избегая конструкторов с длинными списками параметров.
«Шаблон Builder с плавным API» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Проблема телескопического конструктора
Когда у класса много необязательных параметров, количество конструкторов растёт: для 2, 3, 4 параметров и так далее. Паттерн Builder решает эту проблему с помощью плавного интерфейса пошаговой настройки.
// Without builder — hard to read:
Pizza p = new Pizza("large", "thin", true, false, true, false, "mozzarella");Базовая структура Builder
Создайте статический вложенный класс Builder. Внешний класс содержит закрытый конструктор, принимающий объект Builder. Каждый метод установки в Builder возвращает this, обеспечивая цепочку вызовов.
public final class Pizza {
private final String size, crustType, cheese;
private final boolean extraSauce, pepperoni;
private Pizza(Builder b) {
this.size = b.size; this.crustType = b.crustType;
this.cheese = b.cheese; this.extraSauce = b.extraSauce;
this.pepperoni = b.pepperoni;
}
public static class Builder {
private final String size;
private String crustType = "regular", cheese = "mozzarella";
private boolean extraSauce, pepperoni;
public Builder(String size) { this.size = size; }
public Builder crustType(String c) { this.crustType = c; return this; }
public Builder cheese(String c) { this.cheese = c; return this; }
public Builder extraSauce() { this.extraSauce = true; return this; }
public Builder pepperoni() { this.pepperoni = true; return this; }
public Pizza build() { return new Pizza(this); }
}
}Использование плавного интерфейса
Builder читается как предложение. Обязательные параметры передаются в конструктор, а необязательные задаются вызовами методов. Финальный вызов build() создаёт неизменяемый объект.
Pizza p = new Pizza.Builder("large")
.crustType("thin")
.extraSauce()
.pepperoni()
.build();
System.out.println(p);Проверка в build()
Добавьте логику проверки внутрь build() до создания объекта. Для недопустимых сочетаний выбрасывайте IllegalStateException или IllegalArgumentException.
public Pizza build() {
if (size == null || size.isBlank())
throw new IllegalArgumentException("Size required");
if (extraSauce && crustType.equals("stuffed"))
throw new IllegalStateException("No extra sauce on stuffed crust");
return new Pizza(this);
}Builder для неизменяемых объектов
Поскольку внешний класс создаётся из Builder за один шаг, все поля могут быть final, что делает полученный объект полностью неизменяемым и безопасным для многопоточного доступа.
public final class Address {
private final String street, city, country;
private final String postalCode;
private Address(Builder b) { ... } // all finals
// no setters — immutable!
}Обобщённый Builder с типом SELF
Для иерархий наследования используйте рекурсивный параметр обобщённого типа (SELF extends Builder<SELF>), чтобы Builder подкласса возвращал тип подкласса из цепочек методов.
public abstract static class Builder<SELF extends Builder<SELF>> {
String name;
@SuppressWarnings("unchecked")
public SELF name(String n) { this.name = n; return (SELF) this; }
public abstract Vehicle build();
}Lombok @Builder
Lombok создаёт всю инфраструктуру Builder во время компиляции с помощью @Builder. Используйте @Builder.Default для значений полей по умолчанию и @Singular для коллекций.
@Builder
public class Report {
private final String title;
@Builder.Default private final int pageCount = 1;
@Singular private final List<String> authors;
}
// Usage:
Report r = Report.builder().title("Q4").author("Alice").author("Bob").build();Builder в JDK
Многие классы JDK используют интерфейсы в стиле Builder: StringBuilder, HttpRequest.newBuilder(), ProcessBuilder, Stream.Builder. Умейте распознавать этот паттерн.
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Accept", "application/json")
.GET()
.build();Builder и фабрика
Используйте Builder, когда объект требует множества параметров и пошаговой настройки. Используйте фабрику, когда все варианты просты и создание можно выполнить одним вызовом.
Builder для тестовых данных
Builder особенно полезен в тестах: создайте базовый Builder во вспомогательном методе, а затем переопределяйте только поля, относящиеся к конкретному тестовому случаю, сохраняя тесты DRY и удобными для чтения.
User defaultUser() { return new User.Builder("test@example.com").name("Test User").build(); }
User adminUser() { return new User.Builder("admin@example.com").name("Admin").role(ADMIN).build(); }Безопасность потоков
Сам Builder не является безопасным для многопоточного доступа — не делитесь одним Builder между потоками. Продукт, созданный с его помощью, может быть неизменяемым и безопасным для многопоточного доступа, если все поля имеют модификатор final и изменяемые объекты не используются совместно.
Быстрая проверка
Что делает метод Builder «плавным»?
Итоги
Builder решает проблему телескопического конструктора. Используйте статический вложенный класс Builder, возвращайте this из каждого метода установки, выполняйте проверку в build() и создавайте неизменяемый объект. Lombok с помощью @Builder автоматизирует шаблонный код.
Часто задаваемые вопросы
Урок «Шаблон Builder с плавным API» бесплатный?
Да — полный текст урока «Шаблон Builder с плавным API» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Шаблон Builder с плавным API»?
Создавайте сложные объекты пошагово с помощью плавного строителя, избегая конструкторов с длинными списками параметров. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Шаблон Builder с плавным API»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Singleton: потокобезопасные реализации
- Шаблон фабричного метода
- Абстрактная фабрика для семейств продуктов
- Шаблон Builder с плавным API