Builder
Pattern
Construa objetos complexos passo a passo, separando a construção da representação final.
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.GuruPropó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.
● Estruturais
Como montar objetos e classes em estruturas maiores mantendo flexibilidade.
● Comportamentais
Algoritmos e designação de responsabilidades entre objetos.
O Propósito
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 PatternO 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...
// A maioria dos parâmetros fica sem uso na maior parte do tempo
class Casa {
// Chamada horrível — o que significa cada boolean?
const casa = new Casa(
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.
Interface Builder
Define todas as etapas de construção possíveis, comuns a todos os tipos de builders.
Concrete Builders
Implementam as etapas de construção de formas diferentes. Cada builder pode produzir um produto completamente diferente.
Produtos
São os objetos resultantes. Produtos de builders diferentes não precisam compartilhar a mesma interface.
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
+ setParedes(...)
+ setPortas(...)
+ setJanelas(...)
+ setTelhado(...)
+ reset()
+ setParedes(...)
+ setPortas(...)
+ getResultado(): Casa
- portas: number
- janelas: number
- temPiscina: bool
- temGaragem: bool
+ construirCasaSimples()
+ construirMansao()
orquestrar a construção
interface CasaBuilder {
// Concrete Builder
class CasaConcretaBuilder implements CasaBuilder {
// Director — orquestra receitas de construção
class Arquiteto {
// 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
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.
type IBuilder interface {
type Director struct {
func (d *Director) setBuilder(b IBuilder) {
func (d *Director) buildHouse() House {
// main.go
func main() {
Exemplos Práticos
Um HTTP Request Builder simplifica a construção de requisições HTTP complexas. Em vez de passar múltiplos parâmetros para uma função, você encadeia métodos para configurar cada aspecto da requisição de forma legível.
class HTTPRequestBuilder {
// Uso
const request = new HTTPRequestBuilder('https://api.example.com/users')
Um SQL Query Builder permite construir queries complexas de forma programática e intuitiva. Em vez de concatenar strings SQL manualmente, você usa métodos para adicionar cláusulas WHERE, JOINs, ORDER BY e LIMIT, mantendo o código limpo e seguro contra SQL injection.
class QueryBuilder:
}
# Uso
query = QueryBuilder('users')
Prós e Contras
✅ Prós
❌ Contras
Parâmetros
Obrigatórios
Às vezes um objeto não pode existir sem uma determinada propriedade, como um name ou um id. Existem duas formas de garantir isso no Builder.
Opção 1: Construtor do Builder
O parâmetro obrigatório vai direto no constructor do Builder. Sem ele, você nem consegue instanciar o Builder, o erro aparece na hora certa, antes de qualquer método ser chamado.
Ideal quando o parâmetro é estrutural, o objeto simplesmente não faz sentido sem ele.
Opção 2: Validação no build()
O parâmetro pode ser definido em qualquer momento via método encadeado, mas o build() verifica se ele foi informado antes de retornar o objeto. Se não foi, lança um erro.
Ideal quando você quer manter a flexibilidade de ordem nas chamadas, mas ainda impor a regra no final.
// Uso correto
const burger = new BurgerBuilder("Cheddar Burger")
// Erro imediato: não é possível instanciar sem o name
const invalid = new BurgerBuilder() // ← erro aqui
// A ordem das chamadas é livre
const burger = new BurgerBuilder()
// Erro só aparece no final
const invalid = new BurgerBuilder().addBacon().build() // ← erro aqui
Relação com
Outros Padrões
Builder + Bridge
Bridge é um padrão que separa "o que um objeto faz" de "como ele faz". Imagine um controle remoto (abstração) que pode funcionar com qualquer TV (implementação), você troca a TV sem mudar o controle.
No Builder, essa divisão aparece naturalmente: o Director é a abstração (sabe o que construir e em qual ordem), enquanto cada Builder concreto é a implementação (sabe como montar cada parte). Você pode trocar o Builder sem alterar o Director.
Builder + Composite
Composite é um padrão para estruturas em árvore, onde um objeto pode conter outros objetos do mesmo tipo, como uma pasta que contém arquivos e outras pastas.
Construir essa hierarquia manualmente é complicado. O Builder encaixa perfeitamente aqui: você usa seus métodos passo a passo para adicionar nós, filhos e subárvores, deixando o processo organizado e legível, inclusive com chamadas recursivas para ramificações profundas.
Builder vs. Abstract Factory
Abstract Factory também cria objetos, mas o foco é diferente: ele produz famílias inteiras de objetos relacionados de uma vez, como uma fábrica que entrega cadeira, mesa e sofá todos no mesmo estilo.
O Builder, por outro lado, monta um único objeto complexo passo a passo. A diferença prática: se você precisa de controle sobre cada etapa da construção (e quer o objeto só no final), use Builder. Se precisa de vários objetos compatíveis entre si de uma vez, use Abstract Factory.
Builder como Singleton
Singleton é um padrão que garante que uma classe tenha apenas uma instância em toda a aplicação, como uma conexão única com o banco de dados que todos os módulos compartilham.
Em alguns cenários, faz sentido que o próprio Builder (ou a Abstract Factory / Prototype) seja um Singleton: assim, toda a aplicação reutiliza o mesmo builder configurado, evitando criar múltiplas instâncias desnecessárias de um objeto que é caro de inicializar.
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
Participantes
Builder, ConcreteBuilder, Product, Director
Representações
Um processo, infinitos produtos diferentes