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

Приведи пример паттерна Builder в Java

1.2 Junior🔥 181 комментариев
#ORM и Hibernate#Spring Boot и Spring Data#Базы данных и SQL

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

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

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

Пример паттерна Builder в Java

Практический пример: построение SQL запроса

Рассмотрим реалистичный пример - построение SQL запроса с опциональными условиями:

Проблема без Builder

// ❌ Неправильно: слишком много конструкторов
public class QueryBuilder {
    private String select;
    private String from;
    private String where;
    private String orderBy;
    private String limit;
    
    // Конструктор 1: только SELECT FROM
    public QueryBuilder(String select, String from) {}
    
    // Конструктор 2: SELECT FROM WHERE
    public QueryBuilder(String select, String from, String where) {}
    
    // Конструктор 3: SELECT FROM WHERE ORDER BY
    public QueryBuilder(String select, String from, String where, String orderBy) {}
    
    // Конструктор 4: SELECT FROM WHERE ORDER BY LIMIT
    public QueryBuilder(String select, String from, String where, String orderBy, String limit) {}
    
    // Конструктор 5: SELECT FROM ORDER BY
    public QueryBuilder(String select, String from, String orderBy) {}
    
    // ... еще 10+ конструкторов!
    // "Telescoping Constructor" - очень неудобно
}

// Использование (какой конструктор выбрать?)
QueryBuilder query = new QueryBuilder(
    "SELECT id, name, email",
    "FROM users",
    "WHERE age > 18",
    "ORDER BY name",
    "LIMIT 10"
);

Решение: Builder паттерн

// ✅ Правильно: Builder паттерн
public class SqlQuery {
    private String select;
    private String from;
    private String where;
    private String orderBy;
    private String limit;
    
    // Приватный конструктор
    private SqlQuery(Builder builder) {
        this.select = builder.select;
        this.from = builder.from;
        this.where = builder.where;
        this.orderBy = builder.orderBy;
        this.limit = builder.limit;
    }
    
    // Getter'ы
    public String getSelect() { return select; }
    public String getFrom() { return from; }
    public String getWhere() { return where; }
    public String getOrderBy() { return orderBy; }
    public String getLimit() { return limit; }
    
    // Построение SQL строки
    @Override
    public String toString() {
        StringBuilder sql = new StringBuilder();
        sql.append(select).append(" ");
        sql.append(from);
        
        if (where != null) {
            sql.append(" ").append(where);
        }
        if (orderBy != null) {
            sql.append(" ").append(orderBy);
        }
        if (limit != null) {
            sql.append(" ").append(limit);
        }
        
        return sql.toString();
    }
    
    // ============ BUILDER CLASS ============
    public static class Builder {
        private String select;
        private String from;
        private String where;
        private String orderBy;
        private String limit;
        
        // Обязательное поле
        public Builder(String select, String from) {
            this.select = select;
            this.from = from;
        }
        
        // Опциональные поля (возвращаем this для цепочки)
        public Builder where(String where) {
            this.where = where;
            return this;  // для цепочки вызовов
        }
        
        public Builder orderBy(String orderBy) {
            this.orderBy = orderBy;
            return this;
        }
        
        public Builder limit(int limit) {
            this.limit = "LIMIT " + limit;
            return this;
        }
        
        // Финальный метод для создания объекта
        public SqlQuery build() {
            return new SqlQuery(this);
        }
    }
}

// Использование - очень удобно!
SqlQuery query1 = new SqlQuery.Builder(
    "SELECT id, name, email",
    "FROM users"
)
    .where("WHERE age > 18")
    .orderBy("ORDER BY name")
    .limit(10)
    .build();

System.out.println(query1);
// SELECT id, name, email FROM users WHERE age > 18 ORDER BY name LIMIT 10

// Или проще, без WHERE и LIMIT
SqlQuery query2 = new SqlQuery.Builder(
    "SELECT id, name",
    "FROM users"
)
    .orderBy("ORDER BY id DESC")
    .build();

System.out.println(query2);
// SELECT id, name FROM users ORDER BY id DESC

Пример 2: Построение HTTP запроса

public class HttpRequest {
    private String method;
    private String url;
    private Map<String, String> headers;
    private String body;
    private int timeout;
    private boolean followRedirects;
    
    private HttpRequest(Builder builder) {
        this.method = builder.method;
        this.url = builder.url;
        this.headers = builder.headers;
        this.body = builder.body;
        this.timeout = builder.timeout;
        this.followRedirects = builder.followRedirects;
    }
    
    // Выполнение запроса
    public HttpResponse execute() {
        // логика отправки HTTP запроса
        return new HttpResponse();
    }
    
    public static class Builder {
        private String method;
        private String url;
        private Map<String, String> headers = new HashMap<>();
        private String body;
        private int timeout = 30;  // default
        private boolean followRedirects = true;  // default
        
        public Builder(String method, String url) {
            this.method = method;
            this.url = url;
        }
        
        public Builder header(String key, String value) {
            headers.put(key, value);
            return this;
        }
        
        public Builder body(String body) {
            this.body = body;
            return this;
        }
        
        public Builder timeout(int seconds) {
            this.timeout = seconds;
            return this;
        }
        
        public Builder followRedirects(boolean follow) {
            this.followRedirects = follow;
            return this;
        }
        
        public HttpRequest build() {
            return new HttpRequest(this);
        }
    }
}

// Использование
HttpRequest request = new HttpRequest.Builder("POST", "https://api.example.com/users")
    .header("Content-Type", "application/json")
    .header("Authorization", "Bearer token123")
    .body("{ \"name\": \"John\" }")
    .timeout(60)
    .followRedirects(false)
    .build();

HttpResponse response = request.execute();

Пример 3: Построение объекта User (как в реальном проекте)

public class User {
    private Long id;
    private String username;
    private String email;
    private String firstName;
    private String lastName;
    private String phone;
    private LocalDate birthDate;
    private String address;
    private String city;
    private String country;
    private String postCode;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    private boolean active;
    
    // Приватный конструктор
    private User(Builder builder) {
        this.id = builder.id;
        this.username = builder.username;
        this.email = builder.email;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.phone = builder.phone;
        this.birthDate = builder.birthDate;
        this.address = builder.address;
        this.city = builder.city;
        this.country = builder.country;
        this.postCode = builder.postCode;
        this.createdAt = builder.createdAt;
        this.updatedAt = builder.updatedAt;
        this.active = builder.active;
    }
    
    // Getter'ы
    public Long getId() { return id; }
    public String getUsername() { return username; }
    public String getEmail() { return email; }
    // ... остальные getter'ы
    
    // Builder
    public static class Builder {
        private Long id;
        private String username;        // обязательное
        private String email;           // обязательное
        private String firstName;
        private String lastName;
        private String phone;
        private LocalDate birthDate;
        private String address;
        private String city;
        private String country;
        private String postCode;
        private LocalDateTime createdAt;
        private LocalDateTime updatedAt;
        private boolean active = true;  // default true
        
        // Обязательные параметры
        public Builder(String username, String email) {
            this.username = username;
            this.email = email;
        }
        
        // Setter'ы для опциональных параметров
        public Builder id(Long id) {
            this.id = id;
            return this;
        }
        
        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }
        
        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }
        
        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public Builder birthDate(LocalDate birthDate) {
            this.birthDate = birthDate;
            return this;
        }
        
        public Builder address(String address, String city, String country, String postCode) {
            this.address = address;
            this.city = city;
            this.country = country;
            this.postCode = postCode;
            return this;
        }
        
        public Builder createdAt(LocalDateTime createdAt) {
            this.createdAt = createdAt;
            return this;
        }
        
        public Builder updatedAt(LocalDateTime updatedAt) {
            this.updatedAt = updatedAt;
            return this;
        }
        
        public Builder active(boolean active) {
            this.active = active;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

// Использование
User user = new User.Builder("john_doe", "john@example.com")
    .id(1L)
    .firstName("John")
    .lastName("Doe")
    .phone("+1 (555) 123-4567")
    .birthDate(LocalDate.of(1990, 5, 15))
    .address("123 Main St", "New York", "USA", "10001")
    .createdAt(LocalDateTime.now())
    .active(true)
    .build();

// Можно создать более простой объект
User minimalUser = new User.Builder("jane_doe", "jane@example.com")
    .firstName("Jane")
    .lastName("Doe")
    .build();

Использование Lombok для упрощения

В реальных проектах используют Lombok для автоматической генерации Builder'а:

@Data
@Builder
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false)
    private String username;
    
    @Column(unique = true, nullable = false)
    private String email;
    
    private String firstName;
    private String lastName;
    private String phone;
    private LocalDate birthDate;
    
    @Builder.Default
    private boolean active = true;  // default value
    
    @CreationTimestamp
    private LocalDateTime createdAt;
    
    @UpdateTimestamp
    private LocalDateTime updatedAt;
}

// Lombok генерирует всё автоматически!
User user = User.builder()
    .username("john_doe")
    .email("john@example.com")
    .firstName("John")
    .lastName("Doe")
    .phone("+1-555-123-4567")
    .birthDate(LocalDate.of(1990, 5, 15))
    .active(true)
    .build();

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

ПреимуществоОбъяснение
Читаемостьnew User.Builder(...).name("John").email("...")очень понятно
ГибкостьОпциональные параметры, можно пропустить ненужные
МасштабируемостьДобавить новое поле просто (одна строка в Builder'е)
БезопасностьФинальный объект immutable если нет setter'ов
ChainableЦепочка вызовов через return this
ВалидацияМожно валидировать в build() методе

Недостатки Builder паттерна

НедостатокРешение
Много кодаИспользуй Lombok @Builder
Memory overheadBuilder объект занимает память
СложностьПростые объекты лучше с конструктором

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

Используй Builder когда:
✅ Много параметров (> 4)
✅ Много опциональных параметров
✅ Параметры имеют сложные типы
✅ Параметры имеют значения по умолчанию

Не используй Builder когда:
❌ 2-3 параметра
❌ Все параметры обязательные
❌ Простой объект

Вывод

Builder паттерн - это мощный инструмент для создания сложных объектов с опциональными параметрами. Особенно полезен в:

  • REST API (построение запросов)
  • Entity objects в JPA
  • Configuration objects
  • Immutable objects

В современных Java проектах Lombok часто генерирует Builder автоматически, что делает использование паттерна еще более удобным.

Приведи пример паттерна Builder в Java | PrepBro