Menu
Coddy logo textTech

Паттерн Builder

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 93 из 104.

Паттерн Builder отделяет создание сложного объекта от его представления, позволяя пошагово создавать различные конфигурации. Это особенно полезно, когда объект имеет множество необязательных параметров или требует определённой последовательности создания.

Вместо конструктора с множеством параметров (который становится запутанным) Builder предоставляет понятные именованные методы для каждого параметра конфигурации:

#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();
}

Каждый метод-сеттер возвращает ссылку на builder (return *this), обеспечивая цепочку вызовов методов для fluent-интерфейса. Метод build() завершает процесс и возвращает созданный объект.

Используйте Builder при создании объектов с множеством необязательных компонентов, когда вам нужен читаемый код создания или когда один и тот же процесс создания должен создавать разные представления.

challenge icon

Задание

Легко

Давайте создадим систему Computer Builder, которая позволяет пользователям шаг за шагом настраивать пользовательские ПК. Это идеальный сценарий для паттерна Builder: компьютеры имеют множество необязательных компонентов, и мы хотим получить понятный и удобный для чтения способ собирать различные конфигурации.

Вы организуете свой код в трёх файлах:

  • Computer.h: определите product class, представляющий полностью настроенный компьютер.

    Ваш Computer class должен хранить эти компоненты как private-члены: cpu (строка), ram (строка), storage (строка), gpu (строка) и hasWifi (логическое значение). Инициализируйте hasWifi значением false, а строки по умолчанию — пустыми.

    Добавьте public method с именем showSpecs(), который отображает конфигурацию компьютера. Для каждого установленного компонента (непустой строки) выведите его в отдельной строке. Возможность Wi‑Fi должна выводиться только в том случае, если она включена.

  • ComputerBuilder.h: создайте builder class, который конструирует компьютеры с fluent-интерфейсом.

    Ваш ComputerBuilder class должен иметь private-член типа Computer, который он будет постепенно собирать. Implement следующие методы, каждый из которых возвращает ссылку на builder для Enable method chaining:

    • setCPU(const std::string& cpu)
    • setRAM(const std::string& ram)
    • setStorage(const std::string& storage)
    • setGPU(const std::string& gpu)
    • addWifi(): enables возможность Wi‑Fi

    Также Implement метод build(), который возвращает completed объект Computer и сбрасывает builder для возможного повторного использования.

  • main.cpp: объедините всё, чтобы собрать пользовательский компьютер.

    Прочитайте четыре входных значения:

    1. модель CPU (строка)
    2. спецификация RAM (строка)
    3. спецификация хранилища (строка)
    4. следует ли include Wi‑Fi: yes или no

    Используйте ComputerBuilder, чтобы создать компьютер с указанными CPU, RAM и хранилищем. Если значение Wi‑Fi на входе равно yes, также call addWifi(). Обратите внимание, что в этой configuration GPU не указан: builder должен корректно обрабатывать необязательные компоненты.

    После сборки вызовите showSpecs() для полученного компьютера, чтобы отобразить его конфигурацию.

Метод showSpecs() должен выводить данные в следующем формате (показываются только установленные компоненты):

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

Например, для входных значений Intel i7-12700K, 32GB DDR5, 1TB NVMe SSD и yes:

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

Для входных значений AMD Ryzen 5 5600X, 16GB DDR4, 512GB SSD и no:

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

Обратите внимание, как паттерн Builder делает процесс конструирования понятным и гибким. Вы можете легко добавить или пропустить компоненты, а chaining методов создаёт ясный, самодокументируемый код. Строка GPU не появляется, потому что мы никогда её не устанавливаем, что демонстрирует, как builder естественным образом обрабатывает необязательные компоненты.

Попробуйте сами

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

using namespace std;

int main() {
    // Считать входные данные
    string cpu, ram, storage, wifiChoice;
    getline(cin, cpu);
    getline(cin, ram);
    getline(cin, storage);
    getline(cin, wifiChoice);

    // TODO: Создать экземпляр ComputerBuilder
    
    // TODO: Использовать цепочку методов для установки CPU, RAM и storage
    
    // TODO: Если wifiChoice равно "yes", также вызвать addWifi()
    
    // TODO: Вызвать build(), чтобы получить объект Computer
    
    // TODO: Вызвать showSpecs() у собранного компьютера для отображения конфигурации

    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++