← Назад к вопросам

Что такое Building?

1.0 Junior🔥 131 комментариев
#Docker, Kubernetes и DevOps#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Building (Паттерн Builder)

Определение

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

Задача, которую решает Builder

Основная проблема, которую решает Builder:

  • Множество конструкторов — когда у объекта много опциональных параметров
  • Нечитаемость кода — constructor(true, false, 5, null, "value", 123)
  • Невозможность выставить параметры в любом порядке
  • Создание неполных объектов с неправильными начальными значениями
// Плохо: множество конструкторов (Telescoping Constructor Anti-pattern)
public class User {
    private String name;
    private String email;
    private int age;
    private String phone;
    private String address;
    
    public User(String name) { ... }
    public User(String name, String email) { ... }
    public User(String name, String email, int age) { ... }
    public User(String name, String email, int age, String phone) { ... }
    public User(String name, String email, int age, String phone, String address) { ... }
    // И еще 10 вариантов...
}

Классическая реализация Builder

public class User {
    private final String name;
    private final String email;
    private final int age;
    private final String phone;
    private final String address;
    
    // Приватный конструктор — нельзя создать через new
    private User(UserBuilder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }
    
    // Статический вложенный класс Builder
    public static class UserBuilder {
        private String name;           // обязательный
        private String email;          // обязательный
        private int age = 0;           // опциональный с значением по умолчанию
        private String phone = "";
        private String address = "";
        
        // Конструктор Builder принимает обязательные параметры
        public UserBuilder(String name, String email) {
            this.name = name;
            this.email = email;
        }
        
        // Методы для установки опциональных параметров
        public UserBuilder age(int age) {
            this.age = age;
            return this;  // Возвращаем this для цепочки вызовов
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }
        
        // Метод для создания объекта User
        public User build() {
            return new User(this);
        }
    }
}

// Использование
public class Main {
    public static void main(String[] args) {
        User user = new User.UserBuilder("John", "john@example.com")
                .age(30)
                .phone("+1234567890")
                .address("123 Main St")
                .build();
        
        // Или минимальный вариант
        User user2 = new User.UserBuilder("Jane", "jane@example.com").build();
    }
}

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

1. Читаемость кода

// Понятно и самодокументируемо
User user = new User.UserBuilder("Alice", "alice@email.com")
        .age(25)
        .phone("+7900000000")
        .address("Москва")
        .build();

2. Гибкость параметров

  • Можно выставлять параметры в любом порядке
  • Не обязательно выставлять все параметры
  • Легко добавлять новые параметры

3. Неизменяемость объектов

// После build() объект immutable (неизменяемый)
public final class ImmutableUser {
    private final String name;
    
    private ImmutableUser(UserBuilder builder) {
        this.name = builder.name;
    }
    
    // Нет setters — нельзя изменить после создания
}

4. Валидация

public static class UserBuilder {
    public User build() {
        // Валидация перед созданием объекта
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("Name cannot be empty");
        }
        if (email == null || !email.contains("@")) {
            throw new IllegalArgumentException("Invalid email");
        }
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("Invalid age");
        }
        
        return new User(this);
    }
}

Builder в Java стандартной библиотеке

StringBuilder и StringBuffer используют похожий подход:

// StringBuilder — не совсем классический Builder, но похож
String result = new StringBuilder()
        .append("Hello")
        .append(" ")
        .append("World")
        .toString();

// HttpRequest из Java 11+ (реальный Builder)
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.example.com"))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(body))
        .build();

Builder с наследованием

Для иерархии классов можно использовать обобщенный Builder:

public abstract class AbstractUser {
    protected String name;
    protected String email;
    
    protected AbstractUser(AbstractBuilder<?> builder) {
        this.name = builder.name;
        this.email = builder.email;
    }
    
    public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
        protected String name;
        protected String email;
        
        public T name(String name) {
            this.name = name;
            return self();
        }
        
        public T email(String email) {
            this.email = email;
            return self();
        }
        
        protected abstract T self();
        public abstract AbstractUser build();
    }
}

public class PremiumUser extends AbstractUser {
    private String subscribedSince;
    
    protected PremiumUser(PremiumUserBuilder builder) {
        super(builder);
        this.subscribedSince = builder.subscribedSince;
    }
    
    public static class PremiumUserBuilder extends AbstractBuilder<PremiumUserBuilder> {
        private String subscribedSince;
        
        public PremiumUserBuilder subscribedSince(String date) {
            this.subscribedSince = date;
            return this;
        }
        
        @Override
        protected PremiumUserBuilder self() {
            return this;
        }
        
        @Override
        public PremiumUser build() {
            return new PremiumUser(this);
        }
    }
}

Когда использовать Builder

  1. Когда много параметров — особенно опциональных (5+)
  2. Когда нужна неизменяемость — immutable объекты
  3. Когда сложный процесс создания — с валидацией и логикой
  4. Когда API должен быть понятным — самодокументируемый код
  5. Когда параметры часто меняются — легко расширять

Когда NOT использовать Builder

// Не нужен Builder для простого объекта
public class Point {
    private int x;
    private int y;
    
    // Простого конструктора достаточно
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Итоговый вывод

Builder — это элегантное решение для создания сложных объектов. Он делает код более читаемым, гибким и безопасным. Особенно полезен в API-дизайне и при работе с конфигурациями. В современной Java Builder встречается повсюду: от StringBuilder до HttpRequest и frameworkов вроде Spring.