Menu
Coddy logo textTech

Patrón Builder

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 67 de 87.

El patrón Builder es un patrón de diseño creacional que resuelve un problema común: la construcción de objetos complejos con muchos parámetros opcionales. En lugar de crear múltiples constructores o pasar null para parámetros no utilizados, el Builder permite construir objetos paso a paso.

Considera crear un objeto User con campos obligatorios (name, email) y opcionales (age, phone, address). Sin un Builder, necesitarías constructores telescópicos o un constructor desordenado con muchos parámetros. El patrón Builder ofrece un enfoque más limpio:

public class User {
    private final String name;    // obligatorio
    private final String email;   // obligatorio
    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);
        }
    }
}

Los métodos del Builder devuelven this, lo que permite el encadenamiento de métodos—una forma fluida y legible de construir objetos:

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

Observa cómo el constructor User es privado: los objetos solo pueden crearse a través del Builder. Este patrón destaca cuando los objetos tienen muchos campos opcionales, haciendo que tu código sea más legible y menos propenso a errores que las largas listas de parámetros.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de pedidos de pizza utilizando el Builder Pattern! En lugar de lidiar con un constructor que recibe docenas de parámetros para todos los ingredientes y opciones posibles, crearás un constructor fluido que haga que la personalización de la pizza sea limpia y legible.

Organizarás tu código en dos archivos:

  • Pizza.java: Crea una clase Pizza que utilice el Builder Pattern para su construcción. Tu pizza debe tener los siguientes campos:

    size (String) - obligatorio, representa el tamaño de la pizza

    cheese (boolean) - opcional, por defecto es false

    pepperoni (boolean) - opcional, por defecto es false

    mushrooms (boolean) - opcional, por defecto es false

    El constructor de Pizza debe ser privado y aceptar solo un PizzaBuilder como parámetro, copiando todos los valores del builder a los campos de la pizza.

    Incluye un método getDescription() que devuelva una cadena en este formato: [size] Pizza with: [toppings] donde toppings es una lista separada por comas de los ingredientes que son true (Cheese, Pepperoni, Mushrooms). Si no se selecciona ningún ingrediente, la parte de los ingredientes simplemente debe decir no toppings.

    Crea una clase interna estática PizzaBuilder con:

    • Un constructor que reciba el parámetro obligatorio size
    • Métodos cheese(), pepperoni(), y mushrooms() que establezcan cada uno su respectivo booleano a true y devuelvan this para el encadenamiento
    • Un método build() que devuelva una nueva Pizza
  • Main.java: ¡Demuestra tu pizza builder en acción! Recibirás cuatro entradas: el tamaño de la pizza (String), y tres valores yes/no (Strings) que indican si se debe añadir cheese, pepperoni y mushrooms respectivamente.

    Crea un PizzaBuilder con el tamaño dado. Luego, basándote en cada entrada yes/no, encadena los métodos de ingredientes apropiados. Si la entrada es "yes", llama a ese método de ingrediente; si es "no", omítelo. Finalmente, llama a build() para crear tu pizza.

    Imprime el resultado de llamar a getDescription() en tu pizza terminada.

Recibirás cuatro entradas en orden: size (String), add cheese (String: "yes" o "no"), add pepperoni (String: "yes" o "no"), add mushrooms (String: "yes" o "no").

Por ejemplo, con las entradas Large, yes, no, yes, tu salida sería: Large Pizza with: Cheese, Mushrooms

¡Observa cómo el Builder Pattern te permite construir pizzas con cualquier combinación de ingredientes sin necesidad de constructores separados para cada posibilidad!

Hoja de referencia

El Patrón Builder es un patrón de diseño creacional para construir objetos complejos con muchos parámetros opcionales. Evita los constructores telescópicos y las largas listas de parámetros construyendo objetos paso a paso.

Estructura

El patrón consiste en:

  • Una clase con un constructor privado que acepta solo un builder
  • Una clase Builder interna estática que construye el objeto
  • Métodos del Builder que devuelven this para el encadenamiento de métodos
  • Un método build() que crea el objeto final

Ejemplo de Implementación

public class User {
    private final String name;    // obligatorio
    private final String email;   // obligatorio
    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 con Encadenamiento de Métodos

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

El patrón Builder es ideal cuando los objetos tienen muchos campos opcionales, proporcionando un código legible y mantenible en comparación con los constructores con numerosos parámetros.

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer las entradas
        String size = scanner.nextLine();
        String addCheese = scanner.nextLine();
        String addPepperoni = scanner.nextLine();
        String addMushrooms = scanner.nextLine();
        
        // TODO: Crear un PizzaBuilder con el tamaño dado
        // TODO: Encadenar los métodos de ingredientes basados en las entradas yes/no
        // TODO: Construir la pizza e imprimir su descripción
        
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos