O padrão de design Builder tem como objetivo principal simplificar a construção de objetos complexos. Esse padrão é particularmente útil quando um objeto deve ser criado com muitos atributos opcionais ou obrigatórios, ou quando o processo de criação de um objeto é composto por múltiplas etapas e configurações. Os problemas específicos que o padrão Builder tenta resolver incluem:

  1. Construção de Objetos Complexos: O Builder facilita a criação de objetos que possuem múltiplos componentes ou propriedades, especialmente quando algumas dessas propriedades são opcionais. Isso elimina a necessidade de construtores sobrecarregados ou complexos.

  2. Legibilidade e Manutenção: Ao usar o padrão Builder, o código de construção torna-se mais legível e fácil de manter. Ao contrário de uma longa lista de parâmetros em um construtor, que pode ser confusa, o Builder permite a configuração passo a passo com métodos claros.

  3. Imutabilidade de Objetos: O Builder pode ser usado para construir objetos imutáveis sem expor os dados do objeto durante a construção. Uma vez que um objeto é construído, ele não pode ser alterado, o que é particularmente útil em ambientes multithread.

  4. Separação de Responsabilidades: Ele separa a construção de um objeto complexo de sua representação, permitindo que o mesmo processo de construção crie representações diferentes.

  5. Fluência na Interface (Fluent Interface): Os Builders frequentemente utilizam o padrão de Fluent Interface, onde métodos de configuração retornam a própria instância do Builder, permitindo encadeamentos de chamadas de método. Isso torna o código cliente mais expressivo.

  6. Controle sobre o Processo de Construção: O Builder fornece maior controle sobre o processo de construção do objeto, permitindo a construção de um objeto passo a passo e possibilitando a validação em cada etapa.

Em resumo, o padrão Builder é ideal para situações onde você está lidando com objetos que têm muitos parâmetros de construção, especialmente se muitos deles são opcionais ou se a construção é um processo multi-etapas. Ele oferece uma solução mais limpa e organizada do que o uso de múltiplos construtores, construtores com muitos parâmetros ou o padrão JavaBeans.

Exemplo de implementação

Definindo uma classe com uma classe Builder interna

public class Carro {
    private final String marca;
    private final String modelo;
    private final int ano;
    private final String cor;
 
    private Carro(Builder builder) {
        this.marca = builder.marca;
        this.modelo = builder.modelo;
        this.ano = builder.ano;
        this.cor = builder.cor;
    }
 
    public static class Builder {
        private String marca;
        private String modelo;
        private int ano;
        private String cor;
 
        public Builder marca(String marca) {
            this.marca = marca;
            return this;
        }
 
        public Builder modelo(String modelo) {
            this.modelo = modelo;
            return this;
        }
 
        public Builder ano(int ano) {
            this.ano = ano;
            return this;
        }
 
        public Builder cor(String cor) {
            this.cor = cor;
            return this;
        }
 
        public Carro build() {
            return new Carro(this);
        }
    }
 
    // Métodos getters aqui...
}
 

Utilizando o Builder para Criar uma instância

public class Main {
    public static void main(String[] args) {
        Carro carro = new Carro.Builder()
            .marca("Toyota")
            .modelo("Corolla")
            .ano(2020)
            .cor("Preto")
            .build();
 
        System.out.println("Carro criado: " + carro.getModelo());
    }
}