Menu
Coddy logo textTech

ビルダーパターン

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 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();
}

各セッターメソッドはビルダーへの参照(return *this)を返し、流れるようなインターフェースのためのメソッドチェーンを可能にします。build()メソッドは、構築されたオブジェクトを最終確定して返します。

多くのオプションコンポーネントを持つオブジェクトを構築する場合、可読性の高い構築コードが必要な場合、または同じ構築プロセスで異なる表現を作成する必要がある場合に、Builderを使用します。

challenge icon

チャレンジ

簡単

ユーザーがカスタムPCをステップバイステップで構成できるComputer Builderシステムを構築しましょう。これはBuilderパターンの完璧なシナリオです。コンピュータには多くのオプションコンポーネントがあり、さまざまな構成をクリーンで読みやすい方法で組み立てたいからです。

コードは3つのファイルに分けて構成します:

  • Computer.h: 完全に構成されたコンピュータを表すプロダクトクラスを定義します。

    Computerクラスは、これらのコンポーネントをプライベートメンバとして保存する必要があります:cpu (string)、ram (string)、storage (string)、gpu (string)、および hasWifi (boolean)。hasWififalse に、文字列はデフォルトで空に初期化してください。

    コンピュータの構成を表示する showSpecs() というパブリックメソッドを追加します。設定された各コンポーネント(空でない文字列)について、それぞれの行に出力します。Wifi機能は、有効な場合にのみ出力してください。

  • ComputerBuilder.h: 流れるようなインターフェース(fluent interface)でコンピュータを構築するビルダークラスを作成します。

    ComputerBuilderクラスは、構築対象となるプライベートな Computer メンバを持つ必要があります。メソッドチェーンを可能にするために、それぞれビルダーへの参照を返す以下のメソッドを実装してください:

    • setCPU(const std::string& cpu)
    • setRAM(const std::string& ram)
    • setStorage(const std::string& storage)
    • setGPU(const std::string& gpu)
    • addWifi() — Wifi機能を有効にします

    また、完成した Computer オブジェクトを返し、再利用のためにビルダーをリセットする build() メソッドも実装してください。

  • main.cpp: すべてを組み合わせてカスタムコンピュータを構築します。

    4つの入力を読み取ります:

    1. CPUモデル (string)
    2. RAMの仕様 (string)
    3. ストレージの仕様 (string)
    4. Wifiを含めるかどうか: yes または no

    ComputerBuilder を使用して、提供されたCPU、RAM、ストレージを備えたコンピュータを構築します。Wifiの入力が yes の場合は、addWifi() も呼び出します。この構成ではGPUは指定されていないことに注意してください。ビルダーはオプションのコンポーネントを適切に処理する必要があります。

    構築後、生成されたコンピュータの showSpecs() を呼び出して、その構成を表示します。

showSpecs() メソッドは、以下の形式で出力する必要があります(設定されたコンポーネントのみを表示):

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

例えば、入力が Intel i7-12700K32GB DDR51TB NVMe SSD、および yes の場合:

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

入力が AMD Ryzen 5 5600X16GB DDR4512GB SSD、および no の場合:

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

Builderパターンによって構築プロセスがいかに読みやすく柔軟になるかに注目してください。コンポーネントを簡単に追加したりスキップしたりでき、メソッドチェーンによって明確で自己文書化されたコードが作成されます。GPUを設定しなかったためGPUの行が表示されないことは、ビルダーがオプションのコンポーネントを自然に処理する方法を示しています。

チートシート

Builder パターンは、複雑なオブジェクトの構築とその表現を分離し、ステップバイステップでの設定を可能にします。これは、オブジェクトに多くのオプションパラメータがある場合や、特定の構築順序が必要な場合に便利です。

多くのパラメータを持つコンストラクタの代わりに、Builder は各設定オプションに対して明確な名前の付いたメソッドを提供します:

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;  // メソッドチェーンを有効にする
    }
    
    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; }
};

// メソッドチェーンを使用した使用例
Pizza margherita = PizzaBuilder()
    .setDough("thin")
    .setSauce("tomato")
    .setTopping("basil")
    .addCheese()
    .build();

各セッターメソッドは、流れるようなインターフェース(fluent interface)のためのメソッドチェーンを可能にするために return *this を返します。build() メソッドは、構築されたオブジェクトを完成させて返します。

多くのオプションコンポーネントを持つオブジェクトを構築する場合、読みやすい構築コードが必要な場合、または同じ構築プロセスで異なる表現を作成する必要がある場合に 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、ストレージを設定する
    
    // TODO: wifiChoice が "yes" の場合、addWifi() も呼び出す
    
    // TODO: build() を呼び出して Computer オブジェクトを取得する
    
    // TODO: 構築されたコンピュータで showSpecs() を呼び出して構成を表示する

    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン