article thumbnail image
Published 2020. 11. 30. 21:17
  • Builder
    • When piecewise object construction is complicated, provide an API for doing it succintly
    • 빌더 패턴의 목적은 여러 복잡한 요소들의 조합이 필요한 객체를 생성해야 하거나 또는 여러 개의 다양한 객체 집합을 생성해야 할 때 객체 생성만을 전담하는 컴포넌트를 정의하여 객체 생성을 간편하게 하는 것이다.
    • 빌더 패턴은 객체의 생성 과정이 충분히 복잡할 때에만 의미가 있다.
      • Building a string out of substrings
        • web server page rendering
      • Concatenate a single std::string
        • my_text += boost::lexical_cast<string>(my_int);
      • printf("%s = &n", "meaning of life", 42);
      • Boost.Format
        • format("%1,x=%2% : %3%-th try") % "toto" % 40.23 % 50
      • Represent as OO structure and implement operator<< on an object graph

 

// Example.1 빌더 패턴 없이
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
using namespace std;

auto main() -> int {
	// <p>hello</p>
	auto text = "hello";

	string output;
	output += "<p>";
	output += text;
	output += "</p>";

	cout << output << endl;
	//printf("<p>%s</p>", text);

	// <ul><li>hello</li><li>words</li></ul>
	string words[] = { "hello","world" };
	ostringstream oss;
	oss << "<ul>";
	for (auto w : words) {
		oss << " <li>" << w << "</li>";
	}
	oss << "</ul>";
	printf(oss.str().c_str());

	return 0;
}

 

// Example.2 Builder
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
using namespace std;

struct HtmlElement {
	string name;
	string text;
	vector<HtmlElement> elements;
	size_t const indent_size = 2;

	HtmlElement() {};

	HtmlElement(string const& name, string const& text) :
		name{ name }, text{ text }{
	}

	string str(int indent = 0) const {
		ostringstream oss;
		string i(indent_size * indent, ' ');
		oss << i << "<" << name << ">" << endl;
		if (text.size() > 0) {
			oss << string(indent_size * (indent + 1), ' ') << text << endl;
		}

		for (auto const& e : elements) {
			oss << e.str(indent + 1);
		}

		oss << i << "</" << name << ">" << endl;
		return oss.str();
	}
};

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() const {
		return root.str();
	}
};

auto main() -> int {

	HtmlBuilder builder("ul");
	builder.add_child("li", "hello");
	builder.add_child("li", "world");
	cout << builder.str() << endl;
	return 0;
}

 

// Example.3 Fluent Builder
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
using namespace std;

struct HtmlBuilder;

struct HtmlElement
{
    string name;
    string text;
    vector<HtmlElement> elements;
    const size_t indent_size = 2;

    HtmlElement() {}
    HtmlElement(const string& name, const string& text)
        : name(name),
        text(text)
    {
    }

    string str(int indent = 0) const
    {
        ostringstream oss;
        string i(indent_size * indent, ' ');
        oss << i << "<" << name << ">" << endl;
        if (text.size() > 0)
            oss << string(indent_size * (indent + 1), ' ') << text << endl;

        for (const auto& e : elements)
            oss << e.str(indent + 1);

        oss << i << "</" << name << ">" << endl;
        return oss.str();
    }

    static unique_ptr<HtmlBuilder> build(string root_name)
    {
        return make_unique<HtmlBuilder>(root_name);
    }
};

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

    // void to start with
    HtmlBuilder& add_child(string child_name, string child_text)
    {
        HtmlElement e{ child_name, child_text };
        root.elements.emplace_back(e);
        return *this;
    }

    // pointer based
    HtmlBuilder* add_child_2(string child_name, string child_text)
    {
        HtmlElement e{ child_name, child_text };
        root.elements.emplace_back(e);
        return this;
    }

    string str() { return root.str(); }

    operator HtmlElement() const { return root; }
    HtmlElement root;
};

auto main() ->int
{
    // <p>hello</p>
    auto text = "hello";
    string output;
    output += "<p>";
    output += text;
    output += "</p>";
    printf("<p>%s</p>", text);

    // <ul><li>hello</li><li>world</li></ul>
    string words[] = { "hello", "world" };
    ostringstream oss;
    oss << "<ul>";
    for (auto w : words)
        oss << "  <li>" << w << "</li>";
    oss << "</ul>";
    printf(oss.str().c_str());

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


    auto builder2 = HtmlElement::build("ul")
        ->add_child_2("li", "hello")->add_child_2("li", "world");
    cout << builder2 << endl;

    return 0;
}

 

// 그루비 스타일 빌더
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

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

	friend ostream& operator<<(ostream& os, const Tag& tag) {
		os << "<" << tag.name;
		for (const auto& att : tag.attributes) {
			os << " " << att.first << "=\"" << att.second << "\"";
		}

		if (tag.children.size() == 0 && tag.text.length() == 0) {
			os << "/>" << endl;
		}
		else {
			os << ">" << endl;
			if (tag.text.length()) {
				os << tag.text << endl;
			}
			for (const auto& child : tag.children) {
				os << child;
			}
			os << "</" << tag.name << ">" << endl;
		}
		return os;
	}

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 {
	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(make_pair("src", url));
	}
};

auto main() -> int {
	cout <<
		P{
		IMG{"http://entrypoint.tistory.com/image.png"},
		P{"Hello"}
		} 
	<< endl;
	return 0;
}

<p>
<img src="http://entrypoint.tistory.com/image.png"/>
<p>
Hello
</p>
</p>

'Design Pattern' 카테고리의 다른 글

Singleton 싱글턴  (0) 2022.10.25
ProtoType Factory  (0) 2022.03.08
SOLID Design Principles  (0) 2020.11.24
복사했습니다!