Padrão Criacional • GoF

Builder
Pattern

Construa objetos complexos passo a passo, separando a construção da representação final.

por Davi Moreira de Santana

scroll

O que é um
Padrão de Projeto?

Padrões de projeto são soluções típicas para problemas recorrentes no design de software orientado a objetos. Funcionam como plantas arquitetônicas que podem ser adaptadas para resolver problemas específicos no seu código.

Diferente de um algoritmo (que define passos claros para atingir uma meta), um padrão é uma descrição de alto nível de uma solução. Pense assim: um algoritmo é uma receita de comida, com etapas claras. Um padrão é uma planta de obra, onde você vê o resultado final e suas funcionalidades, mas a ordem exata de implementação depende de você.

"O padrão não é um pedaço de código específico, mas um conceito geral para resolver um problema em particular."

Refactoring.Guru
🎯

Propósito

Descreve brevemente o problema e a solução que o padrão endereça.

🔧

Motivação

Explica a fundo o problema e como a solução proposta pelo padrão é viável.

📐

Estrutura

Mostra as classes e objetos envolvidos e como eles se relacionam entre si.

Por que aprender
Padrões de Projeto?

Padrões de projeto são um toolkit de soluções testadas e aprovadas para problemas comuns. Mesmo que você nunca encontre exatamente esses problemas, conhecê-los ensina a resolver todo tipo de desafio usando princípios de design orientado a objetos.

Além disso, padrões definem uma linguagem comum que facilita a comunicação entre desenvolvedores. Ao dizer "use um Builder aqui", toda a equipe entende imediatamente a estrutura proposta, sem precisar de longas explicações.

🧩

Reutilização

Soluções prontas que economizam tempo e reduzem bugs conhecidos no design do software.

💬

Comunicação

Vocabulário compartilhado entre devs. "Builder", "Singleton", "Observer" carregam significado imediato.

🏗️

Arquitetura

Ensinam princípios de design que melhoram toda a qualidade do código produzido.

Classificação
dos Padrões

Os 23 padrões clássicos do GoF (Gang of Four) são divididos em três categorias com base no seu propósito: Criacionais, Estruturais e Comportamentais.

Criacionais

Mecanismos de criação de objetos que aumentam flexibilidade e reutilização.

Factory Method Abstract Factory Builder ★ Prototype Singleton

Estruturais

Como montar objetos e classes em estruturas maiores mantendo flexibilidade.

Adapter Bridge Composite Decorator Facade Flyweight Proxy

Comportamentais

Algoritmos e designação de responsabilidades entre objetos.

Chain of Resp. Command Iterator Mediator Observer State Strategy Visitor

O Propósito

B

Construir objetos complexos passo a passo

O Builder permite produzir diferentes tipos e representações de um objeto usando o mesmo código de construção, sem precisar de um construtor com dezenas de parâmetros.

"O Builder é um padrão de projeto criacional que permite a você construir objetos complexos passo a passo. O padrão permite que você produza diferentes tipos e representações de um objeto usando o mesmo código de construção."

Refactoring.Guru — Builder Pattern

O Problema

Imagine um objeto complexo que necessita de inicialização passo a passo de muitos campos e objetos agrupados. Esse tipo de código de inicialização normalmente fica enterrado dentro de um construtor monstruoso com muitos parâmetros. Ou pior: espalhado por todo o código cliente.

A Analogia da Casa

Para construir uma casa simples, você precisa de paredes, piso, porta, janelas e telhado. Mas e se quiser uma casa maior, com jardim, sistema de aquecimento, encanamento e fiação elétrica?


A abordagem mais simples seria estender a classe base e criar subclasses para cada configuração possível. Mas isso rapidamente leva a uma explosão de subclasses.


Outra opção seria um construtor gigantesco com todos os parâmetros possíveis na classe base. Elimina subclasses, mas cria chamadas monstruosas onde a maioria dos parâmetros fica sem uso.

Observe a construção passo a passo...

❌ O Problema — Construtor Telescópico
// Construtor com parâmetros demais // A maioria dos parâmetros fica sem uso na maior parte do tempo class Casa { constructor( paredes: number, portas: number, janelas: number, temGaragem: boolean, temPiscina: boolean, temJardim: boolean, temEstátuas: boolean, temSistemaAquecimento: boolean, // ... e mais 15 parâmetros ) { } } // Chamada horrível — o que significa cada boolean? const casa = new Casa(4, 1, 4, true, false, true, false, true);

A Solução

O padrão Builder sugere extrair o código de construção do objeto para fora da própria classe e movê-lo para objetos separados chamados builders. O padrão organiza a construção em uma série de etapas (construirParedes(), construirPorta(), etc.). Para criar um objeto, você executa apenas as etapas necessárias.

A parte crucial: você não precisa chamar todas as etapas. Pode invocar apenas aquelas que são necessárias para produzir uma configuração específica.

Etapa 1

Interface Builder

Define todas as etapas de construção possíveis, comuns a todos os tipos de builders.

Etapa 2

Concrete Builders

Implementam as etapas de construção de formas diferentes. Cada builder pode produzir um produto completamente diferente.

Etapa 3

Produtos

São os objetos resultantes. Produtos de builders diferentes não precisam compartilhar a mesma interface.

Etapa 4

Director (Opcional)

Define a ordem de execução das etapas de construção. Encapsula receitas comuns de construção para reutilização.

Estrutura do Padrão Builder

«interface» Builder
+ reset()
+ setParedes(...)
+ setPortas(...)
+ setJanelas(...)
+ setTelhado(...)
CasaBuilder
- casa: Casa
+ reset()
+ setParedes(...)
+ setPortas(...)
+ getResultado(): Casa
Casa (Produto)
- paredes: number
- portas: number
- janelas: number
- temPiscina: bool
- temGaragem: bool
Director
- builder: Builder
+ construirCasaSimples()
+ construirMansao()
usa o builder para
orquestrar a construção
✅ A Solução — Builder Pattern em TypeScript
// Interface Builder interface CasaBuilder { reset(): void; setParedes(n: number): CasaBuilder; setPortas(n: number): CasaBuilder; setJanelas(n: number): CasaBuilder; setPiscina(tem: boolean): CasaBuilder; setGaragem(tem: boolean): CasaBuilder; } // Concrete Builder class CasaConcretaBuilder implements CasaBuilder { private casa: Casa; constructor() { this.reset(); } reset() { this.casa = new Casa(); } setParedes(n) { this.casa.paredes = n; return this; } setPortas(n) { this.casa.portas = n; return this; } setJanelas(n) { this.casa.janelas = n; return this; } setPiscina(t) { this.casa.piscina = t; return this; } setGaragem(t) { this.casa.garagem = t; return this; } getResultado(): Casa { const result = this.casa; this.reset(); return result; } } // Director — orquestra receitas de construção class Arquiteto { construirCasaSimples(builder: CasaBuilder) { builder.reset(); builder.setParedes(4).setPortas(1).setJanelas(4); } construirMansao(builder: CasaBuilder) { builder.reset(); builder.setParedes(12).setPortas(6).setJanelas(20) .setPiscina(true).setGaragem(true); } } // Uso const builder = new CasaConcretaBuilder(); const arquiteto = new Arquiteto(); arquiteto.construirMansao(builder); const mansao = builder.getResultado(); // Ou sem director — construção customizada builder.setParedes(6).setJanelas(8).setPiscina(true); const casaCustom = builder.getResultado();

Builder Interativo

Clique nas etapas para construir seu objeto passo a passo. Veja o output em tempo real.

ETAPAS DE CONSTRUÇÃO

// Clique nas etapas acima para construir... const builder = new CasaBuilder(); builder.reset();

Quando Aplicar
o Builder?

🔩 Objetos com muitas configurações opcionais

Quando o construtor da classe tem 5, 10, 15 parâmetros opcionais, o Builder elimina o "construtor telescópico" e torna a criação legível.

🌲 Construção de árvores Composite ou estruturas complexas

O Builder permite construir produtos passo a passo e defer a execução de algumas etapas sem quebrar o resultado final. Isso é útil para montar árvores de objetos recursivamente.

🔄 Produtos com diferentes representações

Quando o mesmo processo de construção deve produzir representações diferentes do produto (ex: um carro real vs. um manual do carro), builders concretos diferentes resolvem isso.

📦 Isolamento do produto em construção

O Builder mantém o produto privado durante a construção. O código cliente nunca recebe um objeto incompleto ou em estado instável.

Exemplos do Mundo Real

Contexto Builder Produto
Query SQL QueryBuilder String SQL (SELECT...WHERE...)
HTTP Request RequestBuilder Objeto Request configurado
Docker Compose ServiceBuilder docker-compose.yaml
K8s Manifests DeploymentBuilder Deployment + Service + Ingress
StringBuilder append(), insert() String final otimizada

Exemplo Prático
em Go

No exemplo abaixo temos dois builders concretos: NormalBuilder e IglooBuilder. Ambos implementam a mesma interface IBuilder, mas constroem casas completamente diferentes.

builder.go — Interface e Director
package main type IBuilder interface { setDoorType() setWindowType() setNumFloor() getHouse() House } type Director struct { builder IBuilder } func (d *Director) setBuilder(b IBuilder) { d.builder = b } func (d *Director) buildHouse() House { d.builder.setDoorType() d.builder.setWindowType() d.builder.setNumFloor() return d.builder.getHouse() } // main.go func main() { normalBuilder := getBuilder("normal") iglooBuilder := getBuilder("igloo") director := &Director{} director.setBuilder(normalBuilder) normalHouse := director.buildHouse() director.setBuilder(iglooBuilder) iglooHouse := director.buildHouse() }

Prós e Contras

✅ Prós

Construção passo a passo, com possibilidade de adiar etapas ou executá-las recursivamente.
Reutilização do mesmo código de construção para diferentes representações do produto.
Princípio de Responsabilidade Única: isola código de construção complexo da lógica de negócios.
O produto fica privado durante a construção, evitando que o cliente receba objetos incompletos.
Suporte a method chaining, tornando o código cliente fluente e legível.

❌ Contras

Complexidade geral do código aumenta, já que são necessárias novas classes para cada builder e seus produtos.
Para objetos simples com poucos campos, o overhead do Builder pode não compensar.
Em linguagens dinâmicas como Python/JS, named arguments ou object literals muitas vezes resolvem o problema sem precisar do padrão completo.
Pode criar acoplamento entre o builder e os detalhes internos do produto.

Relação com
Outros Padrões

Builder + Bridge

A classe Director age como abstração, enquanto diferentes builders agem como implementações.

Builder + Composite

O Builder pode ser utilizado para construir árvores Composite passo a passo, incluindo chamadas recursivas.

Builder vs. Abstract Factory

Abstract Factory se foca em famílias de objetos relacionados. Builder se foca na construção passo a passo de um objeto complexo.

Builder como Singleton

Builders, Fábricas Abstratas e Protótipos podem todos ser implementados como Singletons quando necessário.

O Builder em
uma frase

"Separe a construção de um objeto complexo da sua representação para que o mesmo processo de construção possa criar diferentes representações."

Gang of Four — Design Patterns (1994)
🏗️

Tipo

Criacional

4

Participantes

Builder, ConcreteBuilder, Product, Director

Representações

Um processo, infinitos produtos diferentes