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, lo que te permite crear distintas 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 (que resulta confuso), 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 de configuración devuelve una referencia al constructor (return *this), lo que permite encadenar métodos para crear una interfaz fluida. El método build() finaliza y devuelve el objeto construido.
Usa Builder cuando construyas objetos con muchos componentes opcionales, cuando quieras un código de construcción legible o cuando el mismo proceso de construcción deba crear distintas representaciones.
Desafío
FácilVamos a crear un sistema Computer Builder que permita a los usuarios configurar PC personalizadas paso a paso. Este es un escenario perfecto para el patrón Builder: las computadoras tienen muchos componentes opcionales y queremos una forma clara y legible de ensamblar distintas configuraciones.
Organizarás el código en tres archivos:
Computer.h: define la clase del producto que representa una computadora completamente configurada.Tu clase
Computerdebe almacenar estos componentes como miembros privados:cpu(cadena),ram(cadena),storage(cadena),gpu(cadena) yhasWifi(booleano). InicializahasWifienfalsey, de forma predeterminada, las cadenas en vacío.Añade un método público llamado
showSpecs()que muestre la configuración de la computadora. Para cada componente que se haya establecido (cadena no vacía), imprímelo en su propia línea. La capacidad wifi solo debe mostrarse si está habilitada.ComputerBuilder.h: crea la clase constructora que construye computadoras con una interfaz fluida.Tu clase
ComputerBuilderdebe tener un miembro privadoComputerque irá construyendo. Implementa estos métodos, cada uno de los cuales devuelve una referencia a la clase constructora para permitir encadenar 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 wifi
Implementa también un método
build()que devuelva el objetoComputerterminado y restablezca la clase constructora para que pueda reutilizarse.main.cpp: integra todo para construir una computadora personalizada.Lee cuatro entradas:
- Modelo de CPU (cadena)
- Especificación de RAM (cadena)
- Especificación de almacenamiento (cadena)
- Si se debe incluir wifi:
yesono
Usa
ComputerBuilderpara construir una computadora con la CPU, la RAM y el almacenamiento proporcionados. Si la entrada de wifi esyes, llama también aaddWifi(). Ten en cuenta que en esta configuración no se especifica ninguna GPU: la clase constructora debe gestionar los componentes opcionales sin problemas.Después de construirla, llama a
showSpecs()en la computadora resultante para mostrar su configuración.
El método showSpecs() debe mostrar la salida con este formato (mostrando solo los componentes establecidos):
CPU: [value]
RAM: [value]
Storage: [value]
GPU: [value]
Wifi: EnabledPor 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: EnabledCon las entradas AMD Ryzen 5 5600X, 16GB DDR4, 512GB SSD y no:
CPU: AMD Ryzen 5 5600X
RAM: 16GB DDR4
Storage: 512GB SSDObserva cómo el patrón Builder hace que el proceso de construcción sea legible y flexible. Puedes añadir u omitir componentes fácilmente, y el encadenamiento de métodos crea un código claro que se explica por sí mismo. La línea de la GPU no aparece porque nunca la establecemos, lo que demuestra cómo las clases constructoras gestionan los componentes opcionales de forma natural.
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "ComputerBuilder.h"
using namespace std;
int main() {
// Lee las entradas
string cpu, ram, storage, wifiChoice;
getline(cin, cpu);
getline(cin, ram);
getline(cin, storage);
getline(cin, wifiChoice);
// TODO: Crea una instancia de ComputerBuilder
// TODO: Usa el encadenamiento de métodos para configurar CPU, RAM y el almacenamiento
// TODO: Si wifiChoice es "yes", llama también a addWifi()
// TODO: Llama a build() para obtener el objeto Computer
// TODO: Llama a showSpecs() en el equipo construido para mostrar la configuración
return 0;
}
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
1Fundamentos de la POO
Archivos externosCompilación y construcción en C++Archivos de cabecera y archivos fuenteEspacios de nombres y ámbitoIntroducción a la POO en C++Clases y objetosEl puntero 'this'Métodos (funciones miembro)Atributos (miembros de datos)Fundamentos de constructores y destructoresRepaso: calculadora sencilla4Propiedades de clase
Miembros de instancia vs. estáticosGetters y settersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases friendRepaso: gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de constructores y destructoresSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualRepaso: jerarquía de empleados10Visión general de STL
Visión general y filosofía de STLContenedores de STLIteradoresAlgoritmos de STLFunctores y expresiones lambdaRepaso: frecuencia de palabras13Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonFactory y Abstract FactoryPatrón BuilderPatrón ObserverPatrón Strategy2Gestión de memoria
Memoria de pila vs. heapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Repaso: gestor de arreglos dinámicos5Encapsulación
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultación de informaciónStruct vs. classClases anidadas e internasRepaso: sistema de registros de estudiantes8Polimorfismo
Polimorfismo en compilación y en tiempo de ejecuciónSobrecarga de funcionesRepaso de las funciones virtualesFunciones virtuales purasClases abstractasDiseño de interfaces en C++Conversión dinámica y RTTIRepaso: calculadora de formas11Conceptos avanzados de POO
Composición frente a herenciaMixins mediante CRTPIdiom PimplBorrado de tiposClases enum y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y destructores
Constructor predeterminadoConstructor con parámetrosConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis detallado del destructorRegla de tres / cinco / ceroRepaso: clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujoSobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tipoRepaso: clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasFundamentos de SFINAE y rasgos de tiposRepaso: contenedor genéricoPractica por tu cuenta: Compilador de C++ online