← Назад к вопросам
Приведи пример паттерна 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 overhead | Builder объект занимает память |
| Сложность | Простые объекты лучше с конструктором |
Когда использовать Builder
Используй Builder когда:
✅ Много параметров (> 4)
✅ Много опциональных параметров
✅ Параметры имеют сложные типы
✅ Параметры имеют значения по умолчанию
Не используй Builder когда:
❌ 2-3 параметра
❌ Все параметры обязательные
❌ Простой объект
Вывод
Builder паттерн - это мощный инструмент для создания сложных объектов с опциональными параметрами. Особенно полезен в:
- REST API (построение запросов)
- Entity objects в JPA
- Configuration objects
- Immutable objects
В современных Java проектах Lombok часто генерирует Builder автоматически, что делает использование паттерна еще более удобным.