Padrão Builder
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 67 de 87.
O Builder Pattern (Padrão Builder) é um padrão de projeto criacional que resolve um problema comum: construir objetos complexos com muitos parâmetros opcionais. Em vez de criar múltiplos construtores ou passar null para parâmetros não utilizados, o Builder permite que você construa objetos passo a passo.
Considere a criação de um objeto User com campos obrigatórios (name, email) e opcionais (age, phone, address). Sem um Builder, você precisaria de construtores telescópicos ou de um construtor confuso com muitos parâmetros. O padrão Builder oferece uma abordagem mais limpa:
public class User {
private final String name; // obrigatório
private final String email; // obrigatório
private final int age; // opcional
private final String phone; // opcional
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}Os métodos do Builder retornam this, permitindo o encadeamento de métodos—uma maneira fluida e legível de construir objetos:
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();Observe como o construtor User é privado—objetos só podem ser criados através do Builder. Este padrão se destaca quando os objetos possuem muitos campos opcionais, tornando seu código mais legível e menos propenso a erros do que longas listas de parâmetros.
Desafio
FácilVamos construir um sistema de pedidos de pizza usando o Builder Pattern! Em vez de lidar com um construtor que recebe dezenas de parâmetros para todas as coberturas e opções possíveis, você criará um builder fluente que torna a personalização da pizza limpa e legível.
Você organizará seu código em dois arquivos:
Pizza.java: Crie uma classePizzaque use o Builder Pattern para construção. Sua pizza deve ter os seguintes campos:size(String) - obrigatório, representa o tamanho da pizzacheese(boolean) - opcional, o padrão é falsepepperoni(boolean) - opcional, o padrão é falsemushrooms(boolean) - opcional, o padrão é falseO construtor de
Pizzadeve ser privado e aceitar apenas umPizzaBuildercomo seu parâmetro, copiando todos os valores do builder para os campos da pizza.Inclua um método
getDescription()que retorne uma string neste formato:[size] Pizza with: [toppings]onde toppings é uma lista separada por vírgulas das coberturas que são true (Cheese, Pepperoni, Mushrooms). Se nenhuma cobertura for selecionada, a parte das coberturas deve apenas dizerno toppings.Crie uma classe interna estática
PizzaBuildercom:- Um construtor que recebe o parâmetro obrigatório
size - Métodos
cheese(),pepperoni()emushrooms()que cada um define seu respectivo booleano como true e retornathispara encadeamento - Um método
build()que retorna uma novaPizza
- Um construtor que recebe o parâmetro obrigatório
Main.java: Demonstre seu pizza builder em ação! Você receberá quatro entradas: o tamanho da pizza (String) e três valores yes/no (Strings) indicando se deve adicionar queijo, pepperoni e cogumelos, respectivamente.Crie um
PizzaBuildercom o tamanho fornecido. Então, com base em cada entrada yes/no, encadeie os métodos de cobertura apropriados. Se a entrada for"yes", chame esse método de cobertura; se for"no", pule-o. Finalmente, chamebuild()para criar sua pizza.Imprima o resultado da chamada de
getDescription()em sua pizza finalizada.
Você receberá quatro entradas em ordem: size (String), add cheese (String: "yes" or "no"), add pepperoni (String: "yes" or "no"), add mushrooms (String: "yes" or "no").
Por exemplo, com as entradas Large, yes, no, yes, sua saída seria: Large Pizza with: Cheese, Mushrooms
Observe como o Builder Pattern permite construir pizzas com qualquer combinação de coberturas sem a necessidade de construtores separados para cada possibilidade!
Folha de consulta
O Builder Pattern (Padrão de Projeto Construtor) é um padrão de projeto criacional para construir objetos complexos com muitos parâmetros opcionais. Ele evita construtores telescópicos e longas listas de parâmetros ao construir objetos passo a passo.
Estrutura
O padrão consiste em:
- Uma classe com um construtor privado que aceita apenas um builder
- Uma classe Builder interna estática que constrói o objeto
- Métodos Builder que retornam
thispara encadeamento de métodos - Um método
build()que cria o objeto final
Exemplo de Implementação
public class User {
private final String name; // obrigatório
private final String email; // obrigatório
private final int age; // opcional
private final String phone; // opcional
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}Uso com Encadeamento de Métodos
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();O padrão Builder é ideal quando os objetos possuem muitos campos opcionais, proporcionando um código legível e de fácil manutenção em comparação com construtores com inúmeros parâmetros.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Ler entradas
String size = scanner.nextLine();
String addCheese = scanner.nextLine();
String addPepperoni = scanner.nextLine();
String addMushrooms = scanner.nextLine();
// TODO: Criar um PizzaBuilder com o tamanho fornecido
// TODO: Encadeie os métodos de cobertura com base nas entradas yes/no
// TODO: Construa a pizza e imprima sua descrição
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator