Padrão Builder
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 93 de 104.
O padrão Builder separa a construção de um objeto complexo de sua representação, permitindo que você crie diferentes configurações passo a passo. Isso é especialmente útil quando um objeto possui muitos parâmetros opcionais ou requer uma sequência de construção específica.
Em vez de um construtor com muitos parâmetros (o que se torna confuso), o Builder fornece métodos claros e nomeados para cada opção de configuração:
#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 retorna uma referência para o builder (return *this), permitindo o encadeamento de métodos para uma interface fluente. O método build() finaliza e retorna o objeto construído.
Use o Builder ao construir objetos com muitos componentes opcionais, quando você deseja um código de construção legível ou quando o mesmo processo de construção deve criar representações diferentes.
Desafio
FácilVamos construir um sistema Computer Builder que permite aos usuários configurar PCs personalizados passo a passo. Este é um cenário perfeito para o padrão Builder — computadores têm muitos componentes opcionais e queremos uma maneira limpa e legível de montar diferentes configurações.
Você organizará seu código em três arquivos:
Computer.h: Defina a classe do produto que representa um computador totalmente configurado.Sua classe
Computerdeve armazenar estes componentes como membros privados:cpu(string),ram(string),storage(string),gpu(string) ehasWifi(boolean). InicializehasWificomofalsee as strings como vazias por padrão.Adicione um método público chamado
showSpecs()que exibe a configuração do computador. Para cada componente que foi definido (string não vazia), imprima-o em sua própria linha. A capacidade wifi só deve ser impressa se estiver ativada.ComputerBuilder.h: Crie a classe builder que constrói computadores com uma interface fluente.Sua classe
ComputerBuilderdeve ter um membro privadoComputerque ela constrói. Implemente estes métodos, cada um retornando uma referência para o builder para permitir o encadeamento de métodos:setCPU(const std::string& cpu)setRAM(const std::string& ram)setStorage(const std::string& storage)setGPU(const std::string& gpu)addWifi()— ativa a capacidade wifi
Também implemente um método
build()que retorna o objetoComputerconcluído e redefine o builder para uma possível reutilização.main.cpp: Reúna tudo para construir um computador personalizado.Leia quatro entradas:
- Modelo da CPU (string)
- Especificação da RAM (string)
- Especificação do armazenamento (string)
- Se deve incluir wifi:
yesouno
Use o
ComputerBuilderpara construir um computador com a CPU, RAM e armazenamento fornecidos. Se a entrada de wifi foryes, chame tambémaddWifi(). Observe que nenhuma GPU é especificada nesta configuração — o builder deve lidar com componentes opcionais de forma graciosa.Após a construção, chame
showSpecs()no computador resultante para exibir sua configuração.
O método showSpecs() deve produzir a saída neste formato (mostrando apenas os componentes que foram definidos):
CPU: [value]
RAM: [value]
Storage: [value]
GPU: [value]
Wifi: EnabledPor exemplo, com as entradas Intel i7-12700K, 32GB DDR5, 1TB NVMe SSD e yes:
CPU: Intel i7-12700K
RAM: 32GB DDR5
Storage: 1TB NVMe SSD
Wifi: EnabledCom as entradas AMD Ryzen 5 5600X, 16GB DDR4, 512GB SSD e no:
CPU: AMD Ryzen 5 5600X
RAM: 16GB DDR4
Storage: 512GB SSDObserve como o padrão Builder torna o processo de construção legível e flexível — você pode facilmente adicionar ou pular componentes, e o encadeamento de métodos cria um código claro e autodocumentado. A linha da GPU não aparece porque nunca a definimos, demonstrando como os builders lidam com componentes opcionais naturalmente.
Folha de consulta
O padrão Builder separa a construção de um objeto complexo de sua representação, permitindo uma configuração passo a passo. É útil quando um objeto possui muitos parâmetros opcionais ou requer uma sequência de construção específica.
Em vez de construtores com muitos parâmetros, o Builder fornece métodos claros e nomeados para cada opção de configuração:
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; // Enable method chaining
}
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; }
};
// Usage with method chaining
Pizza margherita = PizzaBuilder()
.setDough("thin")
.setSauce("tomato")
.setTopping("basil")
.addCheese()
.build();Cada método setter retorna return *this para permitir o encadeamento de métodos (method chaining) para uma interface fluente. O método build() finaliza e retorna o objeto construído.
Use o Builder ao construir objetos com muitos componentes opcionais, quando desejar um código de construção legível ou quando o mesmo processo de construção deva criar representações diferentes.
Experimente você mesmo
#include <iostream>
#include <string>
#include "ComputerBuilder.h"
using namespace std;
int main() {
// Ler as entradas
string cpu, ram, storage, wifiChoice;
getline(cin, cpu);
getline(cin, ram);
getline(cin, storage);
getline(cin, wifiChoice);
// TODO: Criar uma instância de ComputerBuilder
// TODO: Usar encadeamento de métodos para definir CPU, RAM e storage
// TODO: Se wifiChoice for "yes", também chame addWifi()
// TODO: Chamar build() para obter o objeto Computer
// TODO: Chamar showSpecs() no computador construído para exibir a configuração
return 0;
}
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 OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários10Visão Geral da STL
Visão Geral e Filosofia da STLContainers da STLIteradoresAlgoritmos da STLFunctors e Expressões LambdaRecapitulação - Frequência de Palavras13Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico