- 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
- Building a string out of substrings
// 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 |