Patrón Builder: Construcción Paso a Paso de Objetos Complejos
design-patternscreationalbuilder

Intención
El patrón Builder separa la construcción de un objeto complejo de su representación, permitiendo que el mismo proceso de construcción cree diferentes representaciones. Es especialmente útil cuando un objeto tiene muchos parámetros opcionales.
El Problema
¿Has visto constructores como este?
// Constructor telescópico - difícil de usar y mantener
const user = new User(
'John',
'Doe',
'[email protected]',
true,
false,
'premium',
null,
'dark',
['es', 'en']
);Sin mirar la documentación, ¿qué significa cada parámetro? ¿Qué pasa si solo quieres establecer el tema sin modificar el plan?
La Solución: Builder
const user = new UserBuilder()
.withName('John', 'Doe')
.withEmail('[email protected]')
.asVerified()
.withPlan('premium')
.withTheme('dark')
.withLanguages(['es', 'en'])
.build();Cada método es auto-documentado. Solo estableces lo que necesitas.
Diagrama
classDiagram
class Builder {
<<interface>>
+setPartA()
+setPartB()
+build(): Product
}
class ConcreteBuilder {
-product: Product
+setPartA()
+setPartB()
+build(): Product
}
class Director {
-builder: Builder
+construct()
}
class Product {
+partA
+partB
}
Builder <|.. ConcreteBuilder
Director --> Builder
ConcreteBuilder --> ProductImplementación TypeScript
// Producto: Petición HTTP
interface HttpRequest {
method: string;
url: string;
headers: Record<string, string>;
body?: unknown;
timeout: number;
retries: number;
}
// Builder con API fluida
class HttpRequestBuilder {
private request: Partial<HttpRequest> = {
headers: {},
timeout: 30000,
retries: 0,
};
get(url: string): this {
this.request.method = 'GET';
this.request.url = url;
return this;
}
post(url: string): this {
this.request.method = 'POST';
this.request.url = url;
return this;
}
withHeader(key: string, value: string): this {
this.request.headers![key] = value;
return this;
}
withAuth(token: string): this {
return this.withHeader('Authorization', `Bearer ${token}`);
}
withBody(body: unknown): this {
this.request.body = body;
return this.withHeader('Content-Type', 'application/json');
}
withTimeout(ms: number): this {
this.request.timeout = ms;
return this;
}
withRetries(count: number): this {
this.request.retries = count;
return this;
}
build(): HttpRequest {
if (!this.request.method || !this.request.url) {
throw new Error('Method and URL are required');
}
return this.request as HttpRequest;
}
}
// Uso
const request = new HttpRequestBuilder()
.post('https://api.example.com/users')
.withAuth('my-token')
.withBody({ name: 'John' })
.withTimeout(5000)
.withRetries(3)
.build();Director (Opcional)
El Director encapsula configuraciones comunes:
class RequestDirector {
static createAuthenticatedPost(url: string, token: string, body: unknown) {
return new HttpRequestBuilder()
.post(url)
.withAuth(token)
.withBody(body)
.withTimeout(10000)
.withRetries(2)
.build();
}
static createHealthCheck(url: string) {
return new HttpRequestBuilder()
.get(url)
.withTimeout(3000)
.build();
}
}Cuándo Usar
| Situación | Recomendación |
|---|---|
| Objeto con muchos parámetros opcionales | ✅ Recomendado |
| Configuraciones complejas | ✅ Recomendado |
| Construcción paso a paso con validación | ✅ Recomendado |
| Objeto simple con pocos parámetros | ❌ Excesivo |
Conclusión
El patrón Builder es tu mejor aliado para construir objetos complejos de forma legible y mantenible.