Ответ
Паттерн Builder я применяю, когда сталкиваюсь с необходимостью создания сложных объектов, имеющих много конфигурируемых параметров, особенно если часть из них необязательна или имеет значения по умолчанию. Он инкапсулирует логику конструирования и позволяет создавать объекты пошагово, делая код клиента чище и читабельнее.
Проблема, которую он решает:
- Телескопический конструктор: Конструктор с десятком параметров, где большинство —
nullили значения по умолчанию, запутан и подвержен ошибкам. - Неизменяемость (immutability): Если объект должен быть immutable после создания, нельзя использовать сеттеры. Builder позволяет сконфигурировать все поля перед финальным созданием.
Преимущества в использовании:
- Читаемость: Цепочка методов (
builder.setName("X").setPower(100).build()) явно показывает, что конфигурируется. - Гибкость: Можно создавать разные вариации объекта, используя один и тот же процесс построения.
- Изоляция сложности: Логика валидации параметров и сборки объекта скрыта внутри Builder'а.
Пример реализации на Java для конфигурации HTTP-клиента:
public class HttpClient {
private final String baseUrl;
private final int timeout;
private final boolean useCache;
// Приватный конструктор, вызывается только Builder'ом
private HttpClient(Builder builder) {
this.baseUrl = builder.baseUrl;
this.timeout = builder.timeout;
this.useCache = builder.useCache;
}
public static class Builder {
private String baseUrl = "http://localhost"; // Значение по умолчанию
private int timeout = 5000;
private boolean useCache = false;
public Builder baseUrl(String url) { this.baseUrl = url; return this; }
public Builder timeout(int ms) { this.timeout = ms; return this; }
public Builder useCache(boolean flag) { this.useCache = flag; return this; }
public HttpClient build() {
// Можно добавить валидацию параметров здесь
if (timeout <= 0) throw new IllegalArgumentException("Timeout must be positive");
return new HttpClient(this);
}
}
}
// Использование
HttpClient client = new HttpClient.Builder()
.baseUrl("https://api.example.com")
.timeout(10000)
.useCache(true)
.build();