Как создается объект с использованием паттерна Builder?

Ответ

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

Типичная реализация Builder в Java:

  1. Создается статический вложенный класс Builder.
  2. Builder содержит методы-сеттеры (часто называемые по имени параметра) для установки каждого поля, которые возвращают this для поддержки цепочки вызовов (fluent interface).
  3. Финальный метод build() создает и возвращает экземпляр целевого объекта, валидируя параметры при необходимости.

Пример создания неизменяемого (immutable) объекта User:

public class User {
    private final String firstName; // Обязательное поле
    private final String lastName;  // Обязательное поле
    private final int age;          // Опциональное поле
    private final String phone;     // Опциональное поле

    // Приватный конструктор, вызывается из Builder
    private User(Builder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
    }

    // Статический метод для получения Builder
    public static Builder builder(String firstName, String lastName) {
        return new Builder(firstName, lastName);
    }

    // Вложенный класс Builder
    public static class Builder {
        private final String firstName;
        private final String lastName;
        private int age = 0;
        private String phone = "";

        // Конструктор Builder с обязательными полями
        public Builder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public User build() {
            // Здесь может быть валидация параметров
            return new User(this);
        }
    }
}

Использование:

User user = User.builder("John", "Doe")
                .age(30)
                .phone("+1234567890")
                .build();

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

  • Читаемость: Именованные методы делают код создания объекта понятным.
  • Неизменяемость: Целевой объект может быть immutable.
  • Гибкость: Позволяет создавать различные конфигурации объекта, пропуская опциональные параметры.

Ответ 18+ 🔞

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

Вот представь: тебе надо собрать объект, а у него полей — овердохуища, да ещё половина опциональные. Если через конструктор, то это пиздец, Колян, честно. Либо десять конструкторов делать, либо в один пихать кучу null'ов. А тут — красота, блядь!

Смысл-то простой, как три рубля: ты не объект сразу конструируешь, а сначала его чертёж, прототип, так сказать, собираешь по кирпичику. И каждый кирпичик — это метод, который так и называется: .age(), .phone(). И главное, каждый такой метод возвращает тебе самого себя, этого строителя, чтобы можно было цепочкой писать. Это называется fluent interface, а по-нашему — «удобно, блядь».

А потом, когда всё настроил, вызываешь волшебный метод .build(), и он тебе из этого чертежа уже настоящий, готовый и, что важно, неизменяемый объект выдает. Immutable, ёпта! Как кирпичная стена — собрал и забыл, ломай голову.

Смотри, как это выглядит в коде, тут всё чётко:

// Вот наш целевой класс, который будем собирать. Все поля final — менять низя!
public class User {
    private final String firstName; // Обязательное, блядь
    private final String lastName;  // Тоже обязательно
    private final int age;          // А это уже на твой вкус
    private final String phone;     // И это тоже

    // Конструктор приватный! Чтобы только Builder мог его вызывать. Хитро, да?
    private User(Builder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
    }

    // Стартовая точка. Даём строителя, и сразу говорим, что без имени-фамилии — нихуя не получится.
    public static Builder builder(String firstName, String lastName) {
        return new Builder(firstName, lastName);
    }

    // А вот и он, наш герой, вложенный класс Builder!
    public static class Builder {
        private final String firstName; // Обязалово
        private final String lastName;  // Тоже обязалово
        private int age = 0;            // По умолчанию ноль, ебать
        private String phone = "";      // По умолчанию пустота

        // Конструктор строителя — только с обязательными полями.
        public Builder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        // Метод для возраста. Вернёт самого себя (this), чтобы цепочку продолжить.
        public Builder age(int age) {
            this.age = age;
            return this;
        }

        // Метод для телефона. Та же фигня.
        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }

        // Финальный аккорд! Собираем объект и отдаём.
        public User build() {
            // Тут, блядь, можно проверки всякие впендюрить, если что не так.
            // Например, если возраст отрицательный — выбросить исключение, что ли.
            return new User(this);
        }
    }
}

А пользуется этим кто? Да любой, кому не лень, и это охуенно просто:

// Смотри, как лаконично и понятно, ёпта!
User user = User.builder("John", "Doe") // Обязательные поля — сразу
                .age(30)                 // Добавил возраст, если хочешь
                .phone("+1234567890")    // Добавил телефон, если надо
                .build();                // Всё, готово, собираем!

И не надо париться, если телефон не нужен — просто не вызывай .phone(). Красота!

Итог, блядь, преимущества:

  • Читаемость — сразу видно, какие поля и какие значения. Не как в конструкторе на 10 параметров, где нихуя не разберёшь.
  • Неизменяемость — объект после сборки как скала, менять его низя. Безопасно, ёпта.
  • Гибкость — собрал конфигурацию какую хочешь, пропуская что не нужно. Никакого геморроя с кучей конструкторов.

Вот так вот, простой паттерн, а мозги экономит, как будто тебе в рот чих-пых сделали. Удобная штука!