Ответ
Паттерн Builder (Строитель) — это порождающий шаблон проектирования, который позволяет создавать сложные объекты пошагово, отделяя конструирование объекта от его представления. Он особенно полезен для объектов с большим количеством параметров, многие из которых являются необязательными.
Решаемая проблема
Избегание "телескопического конструктора" (множества перегруженных версий с разными наборами параметров) и необходимости передавать null для неиспользуемых полей.
Классическая реализация на Java
public class Computer {
// Обязательные параметры (final)
private final String cpu;
private final String ram;
// Необязательные параметры
private final String storage;
private final String gpu;
// Приватный конструктор, принимает Builder
private Computer(ComputerBuilder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.gpu = builder.gpu;
}
// Статический вложенный класс Builder
public static class ComputerBuilder {
// Обязательные параметры
private final String cpu;
private final String ram;
// Необязательные параметры с значениями по умолчанию
private String storage = "256GB SSD";
private String gpu = "Integrated";
// Конструктор Builder с обязательными параметрами
public ComputerBuilder(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
// Методы для установки необязательных параметров (возвращают this для fluent API)
public ComputerBuilder storage(String storage) {
this.storage = storage;
return this;
}
public ComputerBuilder gpu(String gpu) {
this.gpu = gpu;
return this;
}
// Финальный метод build() создает целевой объект
public Computer build() {
// Здесь можно добавить валидацию параметров
if (cpu == null || ram == null) {
throw new IllegalArgumentException("CPU and RAM are required");
}
return new Computer(this);
}
}
}
// Использование (Fluent Interface):
Computer myPC = new Computer.ComputerBuilder("Intel i7", "16GB DDR4")
.storage("1TB NVMe")
.gpu("NVIDIA RTX 4070")
.build(); // Создается неизменяемый объект Computer
Ключевые преимущества
- Читаемость и ясность: Имена методов (
storage(),gpu()) делают код самодокументируемым. - Гибкость: Позволяет создавать объекты с разными комбинациями параметров, не загромождая класс множеством конструкторов.
- Неизменяемость (Immutability): Целевой объект (
Computer) может быть сделан неизменяемым (finalполя), что повышает надежность в многопоточных средах. - Валидация: Проверку корректности параметров можно централизованно выполнить в методе
build()перед созданием объекта.
Альтернативы в современном Java
- Lombok
@Builder: Генерирует код Builder автоматически. - Record с Builder (в комбинации с библиотеками): Для создания неизменяемых DTO.
Ответ 18+ 🔞
Ну что за жизнь, блядь! Опять этот ваш паттерн Builder, как будто без него мир рухнет. Слушай сюда, я тебе на пальцах объясню, а то смотрю, глаза у тебя уже стеклянные, как у этой самой Муму перед тем, как её в озеро отправили.
Представь, что тебе нужно собрать комп, да? Ну, системный блок, эту железную коробку, которая гудит как пылесос. Так вот, вариантов сборки — овердохуища! Процессор можешь воткнуть один, оперативку другую, видеокарту третью, а про всякие RGB-подсветки, которые только электричество жрут, я вообще молчу.
И что делать? Писать конструктор на 15 параметров? Да ты с ума сошёл! Это ж будет как в том анекдоте: «Видел конструктор? — Нет, но ослышался». Получится телескопический конструктор, блядь, такой длинный, что в один экран не влезет. А если половина параметров не нужна? Придётся null пихать, а это, прости меня, чистой воды распиздяйство.
Вот для этого и придумали Строителя, ёпта! Суть проще пареной репы. Берёшь главный класс, например, Computer, и делаешь ему статический внутренний класс-помощника, ComputerBuilder. Этот помощник — он как тот самый Герасим, здоровый и молчаливый, который всё сделает, но по чёткому плану.
Смотри, как это выглядит в коде, не моргай:
public class Computer {
// Вот это — железо, которое уже впаяно. Final, менять низя.
private final String cpu;
private final String ram;
// А это — опциональное барахло, можно было и не ставить
private final String storage;
private final String gpu;
// Конструктор прячем, чтобы только Builder мог им пользоваться. Хитрая жопа!
private Computer(ComputerBuilder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.gpu = builder.gpu;
}
// А вот и наш красавец, сам Builder!
public static class ComputerBuilder {
// Без этого — никуда. Как водка без закуски.
private final String cpu;
private final String ram;
// А это уже на твой вкус. По умолчанию — что-то скромное.
private String storage = "256GB SSD";
private String gpu = "Integrated";
// Заставляем указать самое главное с самого начала
public ComputerBuilder(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
// А дальше — магия! Каждый метод возвращает самого себя (this).
// Это называется Fluent Interface, звучит умно, а делается просто.
public ComputerBuilder storage(String storage) {
this.storage = storage;
return this;
}
public ComputerBuilder gpu(String gpu) {
this.gpu = gpu;
return this;
}
// И кульминация! Метод build(), который всё это собирает в кучу.
public Computer build() {
// Тут можно проверить, не долбоёб ли ты, и не забыл ли указать процессор.
if (cpu == null || ram == null) {
throw new IllegalArgumentException("CPU and RAM are required, мудак!");
}
return new Computer(this); // Возвращаем готовый, неизменяемый комп!
}
}
}
А теперь, внимание, как этим пользоваться. Это просто песня, а не код:
// Собираем игрового монстра
Computer gamingBeast = new Computer.ComputerBuilder("AMD Ryzen 7", "32GB DDR5")
.storage("2TB NVMe")
.gpu("NVIDIA RTX 4090") // Мечта ипотечника!
.build(); // Всё, готово! Объект создан, поля final, менять нельзя.
// А это — офисный плебейский сишник
Computer officeSlave = new Computer.ComputerBuilder("Intel Celeron", "8GB")
.build(); // storage и gpu остались по умолчанию. И так сойдёт!
Вот видишь? Красиво, читаемо, как будто инструкцию по сборке читаешь. Никаких null, никаких конструкторов на 10 страниц. А главное — объект после build() становится неизменяемым, как скала. В многопоточке это — просто бальзам на душу, терпения ебать ноль на синхронизацию тратить.
Конечно, сейчас все умники используют Lombok с аннотацией @Builder, чтобы не писать этот код вручную. Ну, это как готовую тушёнку брать вместо того, чтобы самого мяса тушить. Удобно, спору нет. Но понимать-то, как оно работает внутри, всё равно надо! А то будешь как тот чувак, который @Builder на Record навесил, а потом орет: «Почему не компилируется, блядь?!».
Так что запомни, дружок: Builder — это когда нужно собрать что-то сложное по кирпичикам, не превращая свою жизнь в ад с телескопическими конструкторами. Всё гениальное — просто, как Муму. Только топить его не надо.