第 2 章 构造器模式
本章所有相关代码:(包含了2.1~2.8的所有代码)
#include<iostream>
#include<string>
#include<vector>
struct HtmlElement
{
std::string name;
std::string text;
std::vector<HtmlElement> elements;
HtmlElement() {
}
HtmlElement(std::string name, std::string text)
:name(name),text(text) {
}
std::string str(int ident = 0) {
if (elements.empty()) {
return "<" + name + "> " + text + " </" + name + ">";
}
std::string res;
res += "<" + name + ">" + text;
for(auto e: elements) {
res += e.str();
}
res += " </" + name + ">";
return res;
}
};
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;
}
HtmlBuilder* add_child2(std::string child_name, std::string child_text) {
root.elements.emplace_back(child_name, child_text);
return this;
}
std::string str() {
return root.str();
}
};
void oop_create_html()
{
std::string words[] = {"hello", "world"};
HtmlElement list{"ul", ""};
for (auto w: words) {
list.elements.emplace_back("li", w);
}
std::cout << list.str() << std::endl;
}
void simple_constructor()
{
HtmlBuilder builder("ul");
builder.add_child("li", "hello world.");
builder.add_child("li", "what that?");
std::cout << builder.str() << std::endl;
}
void flow_constructor()
{
HtmlBuilder builder{"ul"};
builder.add_child("li", "hello world")
.add_child("li", "flow constructor");
std::cout << builder.str() << std::endl;
}
void flow_constructor2()
{
HtmlBuilder *builder = new HtmlBuilder("ul");
builder->add_child2("li", "hello world")
->add_child2("li", "flow constructor 2");
std::cout << builder->str() << std::endl;
}
#include<memory>
struct HtmlBuilder2;
struct HtmlElement2
{
friend struct HtmlBuilder2;
std::string name;
std::string text;
std::vector<HtmlElement2> elements;
const size_t indent_size = 2;
private:
HtmlElement2() {
}
HtmlElement2(std::string name, std::string text)
:name(name),text(text) {
}
public:
static std::unique_ptr<HtmlBuilder2> create(const std::string &root_name) {
return std::make_unique<HtmlBuilder2>(root_name);
}
std::string str(int ident = 0) {
if (elements.empty()) {
return "<" + name + "> " + text + " </" + name + ">";
}
std::string res;
res += "<" + name + ">" + text;
for(auto e: elements) {
res += e.str();
}
res += " </" + name + ">";
return res;
}
};
struct HtmlBuilder2
{
HtmlElement2 root;
operator HtmlElement2() const {
return root;
}
HtmlElement2 build() const{
return root;
}
HtmlBuilder2(std::string root_name) {
root.name = root_name;
}
HtmlBuilder2& add_child(std::string child_name, std::string child_text) {
root.elements.emplace_back(HtmlElement2(child_name, child_text));
return *this;
}
std::string str() {
return root.str();
}
};
void user_to_api()
{
auto builder = HtmlElement2::create("ul");
builder->add_child("li", "hwllo world")
.add_child("li", "user to api");
std::cout << builder->str() << std::endl;
}
void user_to_api_add_op()
{
HtmlElement2 e = HtmlElement2::create("ul")
->add_child("li", "hwllo world")
.add_child("li", "user to api op");
std::cout << e.str() << std::endl;
}
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 << "name: "<< tag.name << ", text:" << tag.text << std::endl;
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) {
std::cout << "test." << std::endl;
}
};
struct IMG:Tag{
explicit IMG(const std::string& url)
:Tag("IMG", "") {
attributes.emplace_back("src", url);
}
};
void test_groovy_style()
{
std::cout <<
P{
IMG{"http://baidu.com"}
}
<< std::endl;
P p{
IMG{"http://baidu.com"}
};
std::cout << p << std::endl;
}
class Person;
class PersonBuilderBase;
class PersonBuilder;
class PersonAddressBuilder;
class PersonJobBuilder;
class Person{
std::string street_address;
std::string post_code;
std::string city;
std::string company_name;
std::string position;
int annual_income = 0;
Person(){}
friend class PersonBuilder;
friend class PersonAddressBuilder;
friend class PersonJobBuilder;
public:
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 {
protected:
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)
{
person.post_code = post_code;
return *this;
}
self& in(std::string city)
{
person.city = city;
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;
return *this;
}
self& as_a(std::string position)
{
person.position = position;
return *this;
}
self& earning(int annual_income)
{
person.annual_income = annual_income;
return *this;
}
};
PersonBuilder Person::create()
{
return PersonBuilder();
}
PersonAddressBuilder PersonBuilderBase::lives() const
{
return PersonAddressBuilder(person);
}
PersonJobBuilder PersonBuilderBase::works() const
{
return PersonJobBuilder(person);
}
void testCombinationConstructor()
{
Person p = Person::create()
.lives()
.at("123 London road")
.with_postcode("SW1 1GB")
.in("london")
.works()
.at("pragmaSoft")
.as_a("Consultant")
.earning(10e6);
}
#include<functional>
class MailService{
class Email
{
public:
std::string from;
std::string to;
std::string subject;
std::string 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 << "from: " << email.from << std::endl
<< "to: " << email.to << std::endl
<< "subject: " << email.subject << std::endl
<< "body: " << email.body << std::endl;
}
};
void testParameterizedConstructor()
{
MailService ms;
ms.send_email([&](auto eb) {
eb.from("foo@bar.com")
.to("bar@baz.com")
.subject("hello")
.body("Hello, how are you?");
});
}
namespace InheritanceOfConstructor
{
class Person
{
public:
std::string name;
std::string position;
std::string date_of_birth;
friend std::ostream &operator<<(std::ostream &os, const Person &obj)
{
return os << "name: " << obj.name
<< "\nposition: " << obj.position
<< "\ndata_of_birth: " << obj.date_of_birth << "\n";
}
};
class PersonBuilder
{
protected:
Person person;
public:
[[nodiscard]] Person build() const
{
return person;
}
};
#if 0
class PersonInfoBuilder : public PersonBuilder
{
public:
PersonInfoBuilder &called(const std::string &name)
{
person.name = name;
return *this;
}
};
class PersonJobBuilder : public PersonInfoBuilder
{
public:
PersonJobBuilder &works_as(const std::string &position)
{
person.position = position;
return *this;
}
};
void testInheritanConstructor()
{
PersonInfoBuilder pb;
auto person = pb.called("Dmitri")
.build();
std::cout << person;
}
#else
template <typename TSelf>
class PersonInfoBuilder : public PersonBuilder
{
public:
TSelf &called(const std::string &name)
{
person.name = name;
return static_cast<TSelf &>(*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 PersonBirthDataBuilder : public PersonJobBuilder<PersonBirthDataBuilder<TSelf>>
{
public:
TSelf &born_on(const std::string &data_of_birth)
{
this->person.date_of_birth = data_of_birth;
return static_cast<TSelf &>(*this);
}
};
class MyBuilder : public PersonBirthDataBuilder<MyBuilder>
{
};
void testInheritanConstructor()
{
MyBuilder mb;
auto me = mb.called("Dmitri")
.work_as("programmer")
.born_on("01/01/1980")
.build();
std::cout << me;
}
void testInheritanConstructor1()
{
MyBuilder mb;
auto me = mb.called("Dmitri");
printf("\n\ntest1: %s\n", typeid(me).name());
me = mb.work_as("programmer");
printf("test2: %s\n", typeid(me).name());
me = mb.born_on("01/01/1980");
printf("test3: %s\n", typeid(me).name());
auto mm = mb.build();
printf("test: %s\n\n", typeid(mm).name());
std::cout << mm;
}
#endif
}
int main()
{
oop_create_html();
simple_constructor();
flow_constructor();
flow_constructor2();
std::cout << std::endl << "================================" << std::endl;
user_to_api();
user_to_api_add_op();
test_groovy_style();
testCombinationConstructor();
testParameterizedConstructor();
InheritanceOfConstructor::testInheritanConstructor1();
InheritanceOfConstructor::testInheritanConstructor();
return 0;
}
关于2.8节中问题的代码
#include<iostream>
#include<string>
class Person
{
public:
std::string name;
std::string position;
std::string date_of_birth;
friend std::ostream &operator<<(std::ostream &os, const Person &obj)
{
return os << "name: " << obj.name
<< "\nposition: " << obj.position
<< "\ndata_of_birth: " << obj.date_of_birth << "\n";
}
};
class PersonBuilder
{
protected:
Person person;
public:
[[nodiscard]] Person build() const
{
return person;
}
};
#if 0
class PersonInfoBuilder : public PersonBuilder
{
public:
PersonInfoBuilder &called(const std::string &name)
{
person.name = name;
return *this;
}
};
class PersonJobBuilder : public PersonInfoBuilder
{
public:
PersonJobBuilder &works_as(const std::string &position)
{
person.position = position;
return *this;
}
};
void testInheritanConstructor()
{
PersonInfoBuilder pb;
auto person = pb.called("Dmitri")
.build();
std::cout << person;
}
#else
template<typename TSelf>
class PersonInfoBuilder : public PersonBuilder
{
public:
TSelf& called(const std::string &name)
{
person.name = name;
return static_cast<TSelf&>(*this);
}
};
template<typename TSelf>
class PersonJobBuilder : public PersonInfoBuilder<TSelf>
{
public:
TSelf& work_as(const std::string &position)
{
this->person.position = position;
return static_cast<TSelf&>(*this);
}
};
template<typename TSelf>
class PersonBirthDataBuilder
:public PersonJobBuilder<TSelf>
{
public:
TSelf& born_on(const std::string& data_of_birth)
{
this->person.date_of_birth = data_of_birth;
return static_cast<TSelf&>(*this);
}
};
class MyBuilder: public PersonBirthDataBuilder<MyBuilder>{
};
void testInheritanConstructor()
{
MyBuilder mb;
auto me = mb.called("Dmitri")
.work_as("programmer")
.born_on("01/01/1980")
.build();
std::cout << me;
}
#endif
int main()
{
PersonBuilder pb;
std::cout << "hello world!" << std::endl;
testInheritanConstructor();
return 0;
}