Menu
Coddy logo textTech

Patrón Builder

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 93 de 104.

El patrón Builder separa la construcción de un objeto complejo de su representación, permitiéndote crear diferentes configuraciones paso a paso. Esto es especialmente útil cuando un objeto tiene muchos parámetros opcionales o requiere una secuencia de construcción específica.

En lugar de un constructor con muchos parámetros (lo cual resulta confuso), el Builder proporciona métodos claros y con nombre para cada opción de configuración:

#include <iostream>
#include <string>

class Pizza {
public:
    std::string dough;
    std::string sauce;
    std::string topping;
    bool cheese;
    
    void describe() const {
        std::cout << dough << " dough, " << sauce << " sauce, "
                  << topping << (cheese ? ", with cheese" : "") << "\n";
    }
};

class PizzaBuilder {
private:
    Pizza pizza;
    
public:
    PizzaBuilder& setDough(const std::string& d) {
        pizza.dough = d;
        return *this;
    }
    
    PizzaBuilder& setSauce(const std::string& s) {
        pizza.sauce = s;
        return *this;
    }
    
    PizzaBuilder& setTopping(const std::string& t) {
        pizza.topping = t;
        return *this;
    }
    
    PizzaBuilder& addCheese() {
        pizza.cheese = true;
        return *this;
    }
    
    Pizza build() { return pizza; }
};

int main() {
    Pizza margherita = PizzaBuilder()
        .setDough("thin")
        .setSauce("tomato")
        .setTopping("basil")
        .addCheese()
        .build();
    
    margherita.describe();
}

Cada método setter devuelve una referencia al builder (return *this), lo que permite el encadenamiento de métodos para una interfaz fluida. El método build() finaliza y devuelve el objeto construido.

Utilice Builder al construir objetos con muchos componentes opcionales, cuando desee un código de construcción legible o cuando el mismo proceso de construcción deba crear diferentes representaciones.

challenge icon

Desafío

Fácil

Vamos a construir un sistema Computer Builder que permita a los usuarios configurar PCs personalizados paso a paso. Este es un escenario perfecto para el patrón Builder: las computadoras tienen muchos componentes opcionales y queremos una forma limpia y legible de ensamblar diferentes configuraciones.

Organizarás tu código en tres archivos:

  • Computer.h: Define la clase de producto que representa una computadora completamente configurada.

    Tu clase Computer debe almacenar estos componentes como miembros privados: cpu (string), ram (string), storage (string), gpu (string) y hasWifi (boolean). Inicializa hasWifi en false y los strings como vacíos por defecto.

    Agrega un método público llamado showSpecs() que muestre la configuración de la computadora. Para cada componente que haya sido establecido (string no vacío), imprímelo en su propia línea. La capacidad de wifi solo debe imprimirse si está habilitada.

  • ComputerBuilder.h: Crea la clase builder que construye computadoras con una interfaz fluida.

    Tu clase ComputerBuilder debe tener un miembro privado Computer que irá construyendo. Implementa estos métodos, cada uno devolviendo una referencia al builder para permitir el encadenamiento de métodos:

    • setCPU(const std::string& cpu)
    • setRAM(const std::string& ram)
    • setStorage(const std::string& storage)
    • setGPU(const std::string& gpu)
    • addWifi() — habilita la capacidad de wifi

    También implementa un método build() que devuelva el objeto Computer completado y reinicie el builder para una posible reutilización.

  • main.cpp: Une todo para construir una computadora personalizada.

    Lee cuatro entradas:

    1. Modelo de CPU (string)
    2. Especificación de RAM (string)
    3. Especificación de almacenamiento (string)
    4. Si se debe incluir wifi: yes o no

    Usa el ComputerBuilder para construir una computadora con la CPU, RAM y almacenamiento proporcionados. Si la entrada de wifi es yes, llama también a addWifi(). Ten en cuenta que no se especifica ninguna GPU en esta configuración; el builder debe manejar los componentes opcionales con elegancia.

    Después de construir, llama a showSpecs() en la computadora resultante para mostrar su configuración.

El método showSpecs() debe producir una salida en este formato (mostrando solo los componentes que fueron establecidos):

CPU: [value]
RAM: [value]
Storage: [value]
GPU: [value]
Wifi: Enabled

Por ejemplo, con las entradas Intel i7-12700K, 32GB DDR5, 1TB NVMe SSD y yes:

CPU: Intel i7-12700K
RAM: 32GB DDR5
Storage: 1TB NVMe SSD
Wifi: Enabled

Con las entradas AMD Ryzen 5 5600X, 16GB DDR4, 512GB SSD y no:

CPU: AMD Ryzen 5 5600X
RAM: 16GB DDR4
Storage: 512GB SSD

Observa cómo el patrón Builder hace que el proceso de construcción sea legible y flexible: puedes agregar o saltar componentes fácilmente, y el encadenamiento de métodos crea un código claro y autodocumentado. La línea de GPU no aparece porque nunca la configuramos, lo que demuestra cómo los builders manejan los componentes opcionales de forma natural.

Hoja de referencia

El patrón Builder separa la construcción de un objeto complejo de su representación, permitiendo una configuración paso a paso. Es útil cuando un objeto tiene muchos parámetros opcionales o requiere una secuencia de construcción específica.

En lugar de constructores con muchos parámetros, el Builder proporciona métodos claros y con nombre para cada opción de configuración:

class Pizza {
public:
    std::string dough;
    std::string sauce;
    std::string topping;
    bool cheese;
};

class PizzaBuilder {
private:
    Pizza pizza;
    
public:
    PizzaBuilder& setDough(const std::string& d) {
        pizza.dough = d;
        return *this;  // Habilitar el encadenamiento de métodos
    }
    
    PizzaBuilder& setSauce(const std::string& s) {
        pizza.sauce = s;
        return *this;
    }
    
    PizzaBuilder& setTopping(const std::string& t) {
        pizza.topping = t;
        return *this;
    }
    
    PizzaBuilder& addCheese() {
        pizza.cheese = true;
        return *this;
    }
    
    Pizza build() { return pizza; }
};

// Uso con encadenamiento de métodos
Pizza margherita = PizzaBuilder()
    .setDough("thin")
    .setSauce("tomato")
    .setTopping("basil")
    .addCheese()
    .build();

Cada método setter devuelve return *this para habilitar el encadenamiento de métodos para una interfaz fluida. El método build() finaliza y devuelve el objeto construido.

Utilice Builder al construir objetos con muchos componentes opcionales, cuando desee un código de construcción legible o cuando el mismo proceso de construcción deba crear diferentes representaciones.

Pruébalo tú mismo

#include <iostream>
#include <string>
#include "ComputerBuilder.h"

using namespace std;

int main() {
    // Leer entradas
    string cpu, ram, storage, wifiChoice;
    getline(cin, cpu);
    getline(cin, ram);
    getline(cin, storage);
    getline(cin, wifiChoice);

    // TODO: Crear una instancia de ComputerBuilder
    
    // TODO: Usar el encadenamiento de métodos para establecer CPU, RAM y storage
    
    // TODO: Si wifiChoice es "yes", llamar también a addWifi()
    
    // TODO: Llamar a build() para obtener el objeto Computer
    
    // TODO: Llamar a showSpecs() en la computadora construida para mostrar la configuración

    return 0;
}
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