2.2简单构造器模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

struct HtmlElement
{
std::string name, text;
std::vector<HtmlElement> elements;

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

std::string str(int indent = 0)const
{
std::ostringstream oss;
std::string indentation(indent * 2, ' ');//两个空格缩进
//开始标签
oss << indentation << "<" << name << ">" << std::endl;

//文本内容
if (!text.empty())
oss << indentation << text << std::endl;

//子元素
for (const auto&e : elements)
oss << e.str(indent + 1); //递归调用, 增加缩进层次

//结束标签
oss << indentation << "</" << name << ">" << std::endl;

return oss.str();
}
};

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

void add_child(std::string child_name, std::string child_text)
{
root.elements.emplace_back(child_name, child_text);
}

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

int main(void)
{
/*
std::string words[] = {"hello", "world"};
HtmlElement list{"ul", ""};

for (auto w : words)
list.elements.emplace_back("li", w);
printf(list.str().c_str());
printf("\n");
*/

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

2.3流式模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

struct HtmlElement
{
std::string name, text;
std::vector<HtmlElement> elements;

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

std::string str(int indent = 0)const
{
std::ostringstream oss;
std::string indentation(indent * 2, ' ');//两个空格缩进
//开始标签
oss << indentation << "<" << name << ">" << std::endl;

//文本内容
if (!text.empty())
oss << indentation << text << std::endl;

//子元素
for (const auto&e : elements)
oss << e.str(indent + 1); //递归调用, 增加缩进层次

//结束标签
oss << indentation << "</" << name << ">" << std::endl;

return oss.str();
}
};

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

HtmlBuilder& add_child(std::string child_name, std::string child_text)
{
root.elements.emplace_back(child_name, child_text);
return *this;
}

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


int main(void)
{
/*
std::string words[] = {"hello", "world"};
HtmlElement list{"ul", ""};

for (auto w : words)
list.elements.emplace_back("li", w);
printf(list.str().c_str());
printf("\n");
*/

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

2.4 用户传达意图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <memory>
struct HtmlBuilder;

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

private:
// hide all constructors
HtmlElement() {}
HtmlElement(const std::string& name, const std::string& text) : name(name), text(text) {}
public:
static std::unique_ptr<HtmlBuilder> create(const std::string& root_name)
{
return std::make_unique<HtmlBuilder>(root_name);
}
std::string str(int indent = 0)const
{
std::ostringstream oss;
std::string indentation(indent * 2, ' ');//两个空格缩进
//开始标签
oss << indentation << "<" << name << ">" << std::endl;

//文本内容
if (!text.empty())
oss << indentation << text << std::endl;

//子元素
for (const auto&e : elements)
oss << e.str(indent + 1); //递归调用, 增加缩进层次

//结束标签
oss << indentation << "</" << name << ">" << std::endl;

return oss.str();
}

};

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

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

static HtmlBuilder build(const std::string& root_name) {
return (*HtmlElement::create(root_name));
}

HtmlBuilder& add_child(std::string child_name, std::string child_text)
{
root.elements.emplace_back(HtmlElement(child_name, child_text));
return *this;
}

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

int main(void)
{
/*
auto builder = HtmlElement::create("ul");
builder->add_child("li", "hello")->add_child("li", "world");
std::cout << (*builder).str() << std::endl;
*/
HtmlBuilder builder2 = HtmlBuilder::build("ul")
.add_child("li", "hello")
.add_child("li", "world");
std::cout << builder2.str() << std::endl;
}

2.5 groovy风格的构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include <vector>
#include <string>
#include <initializer_list>

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

friend std::ostream& operator<<(std::ostream& os, const Tag& tag)
{
// 输出标签名
os << "<" << tag.name;

// 输出属性
for (const auto& attribute : tag.attributes)
{
os << " " << attribute.first << "=" << "\"" << attribute.second << "\"";
}

// 输出子标签
for (const auto& child : tag.children)
{
os << ">" << child << "</" << child.name << ">";
}

// 输出文本内容
if (!tag.text.empty())
{
os << ">" << tag.text << "</" << tag.name;
}
else
{
os << "/>";
}


return os;
}

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

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

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

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


int main(int argc, char* argv[])
{
std::cout <<

P {
IMG {"http://pokemon.com/pikachu.png"}
}

<< std::endl;

return 0;
}

2.6 组合构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <iostream>
#include <cstdlib>
#include <memory>

class Person;
class PersonBuilder;
class PersonBuilderBase;
class PersonAddressBuilder;
class PersonJobBuilder;

class Person
{
// address
std::string street_address, post_code, city;

// employment
std::string company_name, position;
int amual_income = 0;

Person() {}
public:
friend class PersonBuilder;
friend class PersonAddressBuilder;
friend class PersonJobBuilder;
/*
static std::unique_ptr<PersonBuilderBase> create()
{
static Person defaultPerson;
return std::make_unique<PersonBuilderBase>(defaultPerson);
}
*/
static PersonBuilder create();
};

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 PersonBuilder : 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;
std::cout << "street_address is " << street_address << std::endl;
return *this;
}

self& with_postcode(std::string post_code)
{
person.post_code = post_code;
std::cout << "post_code is " << post_code << std::endl;
return *this;
}
self& in(std::string city)
{
person.city = city;
std::cout << "city is " << city << std::endl;
return *this;
}
};

class PersonJobBuilder : public PersonBuilderBase
{
typedef PersonJobBuilder self;
public:
explicit PersonJobBuilder(Person& person)
: PersonBuilderBase { person } {}
self& at(std::string company_name)
{
person.company_name = company_name;
std::cout << "company is " << company_name << std::endl;
return *this;
}
self& as_a(std::string position)
{
person.position = position;
std::cout << "position is " << position << std::endl;
return *this;
}
self& earning(int amual_income)
{
person.amual_income = amual_income;
std::cout << "amual_income is " << amual_income << std::endl;
return *this;
}
};


PersonAddressBuilder PersonBuilderBase::lives() const
{
return PersonAddressBuilder(person);
};

PersonJobBuilder PersonBuilderBase::works() const
{
return PersonJobBuilder(person);
};

PersonBuilder Person::create()
{
return PersonBuilder();
}

int main(void)
{
Person p = Person::create()
.lives().at("123 London Road")
.with_postcode("SW1 1GB")
.in("London")
.works().at("PragmaSoft")
.as_a("Consultant")
.earning(10e6);
return 0;
}

2.7 参数构造模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <functional>

class MailService
{
class Email
{
public:
std::string from, to, subject, body;
};
public:
class EmailBuilder
{
Email& email;
public:
explicit EmailBuilder(Email &email) : email(email) {}
EmailBuilder& from(std::string from)
{
email.from = from;
return *this;
}
EmailBuilder& to(std::string to)
{
email.to = to;
return *this;
}
EmailBuilder& subject(std::string subject)
{
email.subject = subject;
return *this;
}
EmailBuilder& body(std::string body)
{
email.body = body;
return *this;
}
};

void send_email(std::function<void(EmailBuilder&)> builder)
{
Email email;
EmailBuilder b{email};
builder(b);
send_email_impl(email);
}

private:
void send_email_impl(const Email& email)
{
std::cout << "send " << email.body << " from " << email.from
<< " to " << email.to << " success" << std::endl;
}
};

int main(void)
{
MailService ms;
ms.send_email([&](auto& eb){
eb.from("foo@bar.com")
.to("bar@baz.com")
.subject("hello")
.body("Hello, how are you?");
});

return 0;
}

2.8 构造器模式的继承性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <string>
#include <typeinfo>

class Person
{
public:
std::string name, position, date_of_birth;
friend std::ostream& operator<<(std::ostream& os, const Person& obj)
{
return os
<< "name: " << obj.name << std::endl
<< "position: " << obj.position << std::endl
<< "date_of_birth: " << obj.date_of_birth << std::endl;
}
};

class PersonBuilder
{
protected:
Person person;
public:
[[nodiscard]] Person build() const {
return person;
}
};

template <typename TSelf>
class PersonInfoBuilder : public PersonBuilder
{
public:
TSelf& called(const std::string& name)
{
person.name = name;
return static_cast<TSelf&>(*this);
// alternatively, *static_cast<TSelf*>(this)
//return *this;
}
};

template <typename TSelf>
class PersonJobBuilder
: public PersonInfoBuilder<PersonJobBuilder<TSelf>>
{
public:
TSelf& work_as(const std::string& position)
{
this->person.position = position;
return static_cast<TSelf&>(*this);
}
};


template <typename TSelf>
class PersonBirthDateBuilder
: public PersonJobBuilder<PersonBirthDateBuilder<TSelf>>
{
public:
TSelf& born_on(const std::string& date_of_birth)
{
this->person.date_of_birth = date_of_birth;
return static_cast<TSelf&>(*this);
}
};

class MyBuilder : public PersonBirthDateBuilder<MyBuilder> {};

int main(void)
{
//PersonJobBuilder pb;
MyBuilder mb;
/*
auto person =
pb.called("Dmitri")
.works_as("Programmer") //will not complie
.build();
*/
auto me =
mb.called("Dmitri")
.work_as("Programmer")
.born_on("01/01/1980")
.build();

std::cout << me;
return 0;
}