Modern C++ Design Pattern/Chatper 2. 빌더

created : 2020-04-07T11:44:17+00:00
modified : 2020-09-26T14:10:55+00:00

Builder Pattern

Simple Builder

    struct HtmlBuilder
    {
      HtmlElement root;

      HtmlBuilder(string root_name) { root.name = root_name; }

      void add_child(string child_name string child_text)
      {
        HtmlElement e{ child_name, child_text };
        root.elements.emplace_back(e);
      }
      string str() { return root.str(); }
    };

Fluent Builder

    struct HtmlBuilder
    {
      HtmlElement root;
      HtmlBuilder(string root_name) { root.name = root_name; }
      HtmlBuilder& add_child(string child_name string child_text)
      {
        HtmlElement e{ child_name child_text };
        root.elements.emplace_back(e);
        return *this;
      }
      /* skip */
    };

    HtmlBuilder builder{ "ul" };
    builder.add_child("li", "Hello").add_child("li", "world");
    cout << builder.str() << endl;

Force to use Builder Class

Groovy - style builder

    struct Tag
    {
      string name;
      string text;
      vector<Tag> children;
      vector<pair<string, string> > sttributes;

      friend ostream& operator << (std::ostream& os, const Tag& tag)
      {
      /* skip implementation */
      }

    protected:
      Tag(const string& name, const string& text)
        : name {name}, text{text} {}

      Tag(const string &name, const vector<Tag>& children)
        : name{name}, children{children} {}
    };

    struct P : Tag
    {
      explicit P(const string& text)
        : Tag{"p", text} {}

      P(initializer_list<Tag> children)
        : Tag{"p", children} {}
    };

    struct IMG : Tag
    {
      explicit IMG(const string& url
        : Tag{"img", ""}
      {
        attributes.emplace_back({"src", url});
      }
    };

    std::cout <<
      P {
        IMG { "http://pokemon.com/pikachu.png" }
      }
    << std::endl;

Composite Builder

    class PersonBuilderBase
    {
    protected:
      Person& person;
      explicit PersonBuilderBase(Person& person)
        : person{ person } {}
    public:
      operator Person()
      {
        return std::move(person);
      }

      PersonAddressBuilder lives() const;
      PersonJobBuilder works() const;
    };

    class PersonBiulder : public PersonBuilderBase
    {
      Person p;
    public:
      PersonBuilder() : PersonBuilderBase{p} {}
    };


    class PersonAddressBuilder : public PersonBuilderBase
    {
      typedef PersonAddressBuilder self;
    public:
      explicit PersonAddressBuilder(Person& person)
        : PersonBuilderBase { person } {}

      self& at(std::string street_address)
      {
        person.street_address = street_address;
        return *this;
      }

      self& with_postcode(std::string post_code) { /* skip */ }

      self& in(std::string city) { /* skip */ }
    };

    Person p = Person::create()
      .lives().at("123 London Road")
              .with_postcode("SW1 1GB")
              .in("London")
      .works().at("PragmaSoft")
              .as_a("Consultant")
              .earning(10e6);

Summary