《C++20设计模式》学习笔记代码---构造器模式

第 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) {
        
    }

    // 该函数用来实现把elements元素拼接为字符串
    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.name + "> " + e.text;
            res += e.str(); // 递归处理, 对子元素的的子元素处理
            // res += " </" + e.name + ">";
        }
        res += " </" + name + ">";

        return res;
    }
};


/* 该类是用于构建HTML元素的组件*/
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);
    // }

    /*
     * 流式构造器
    */
    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{"ul"};
    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);
    }
    // 该函数用来实现把elements元素拼接为字符串
    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.name + "> " + e.text;
            res += e.str(); // 递归处理, 对子元素的的子元素处理
            // res += " </" + e.name + ">";
        }
        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) {
        // 由于HtmlElement2的构造函数为protected, 所以需要在HtmlElement2把HtmlBuilder2设位HtmlElement2的友元类
        // 在这块遇到了个问题, 不能直接使用参数写到elements中,需把创建好的类型然后作为emplace_back的参数传入
        // 该问题的原因是由于HtmlElement2的构造函数是保护成员,把child_name和child_text作为参数传入emplace_back
        // vector内部会创建HtmlElement2导致报错
        // root.elements.emplace_back(child_name, 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
{
    // 在 C++ 中,explicit 是一个关键字,用于声明只能通过显式调用来调用的构造函数。
    // 这可以防止编译器进行隐式类型转换,从而提高代码的可读性和安全性。
    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{
    // address
    std::string street_address;
    std::string post_code;
    std::string city;

    // employment
    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);
    }

    // builder facets
    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);
}
//================================================================//

// 2.7 参数化构造器
//----------------------------------------------------------------//
#include<functional>

class MailService{
    class Email
    {
    public:
        std::string from;
        std::string to;
        std::string subject;
        std::string body;
        // possibly other members here
    };

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;
        }
        // other fluent members here
    };

    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)
    {
        // actually send the 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?");
    });
}
//----------------------------------------------------------------//


// 2.8 构造器模式的继承性
namespace InheritanceOfConstructor
{
    // constructor_2_8.cpp
    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:
        // PersonBuilder(){}
        // PersonBuilder(Person &person) : person{person} {}
        // [[nodiscard]] :C++17引入的语法
        // 当用于描述函数的返回值时,如果调用函数的地方没有获取返回值时,编译器会给予警告
        // 当用于描述类或枚举时,若果函数的返回值是该类或枚举的对象时(引用和指针不可以),如果该返回值没有被获取,编译器给予警告。
        [[nodiscard]] Person build() const
        {
            return person;
        }
    };

#if 0
    class PersonInfoBuilder : public PersonBuilder
    {
    public:
        // PersonInfoBuilder(){}
        // explicit PersonInfoBuilder(Person &person) : PersonBuilder(person) {}
        PersonInfoBuilder &called(const std::string &name)
        {
            person.name = name;
            return *this;
        }
    };

    class PersonJobBuilder : public PersonInfoBuilder
    {
    public:
        // explicit PersonJobBuilder(Person &person) : PersonInfoBuilder(person) {}
        PersonJobBuilder &works_as(const std::string &position)
        {
            person.position = position;
            return *this;
        }
    };

    void testInheritanConstructor()
    {
        PersonInfoBuilder pb;
        auto person = pb.called("Dmitri")
                          //.work_as("programmer") // will not compile
                          .build();
        std::cout << person;
    }
#else

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

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

    template <typename TSelf>
    // class PersonBirthDataBuilder : public PersonJobBuilder<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") // will not compile
                      .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"); // will not compile
        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
} // namespace InheritanceOfConstructor

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:
    // PersonBuilder(){}
    // PersonBuilder(Person &person) : person{person} {}
    // [[nodiscard]] :C++17引入的语法
    // 当用于描述函数的返回值时,如果调用函数的地方没有获取返回值时,编译器会给予警告
    // 当用于描述类或枚举时,若果函数的返回值是该类或枚举的对象时(引用和指针不可以),如果该返回值没有被获取,编译器给予警告。
    [[nodiscard]] Person build() const
    {
        return person;
    }
};

#if 0
class PersonInfoBuilder : public PersonBuilder
{
public:
    // PersonInfoBuilder(){}
    // explicit PersonInfoBuilder(Person &person) : PersonBuilder(person) {}
    PersonInfoBuilder &called(const std::string &name)
    {
        person.name = name;
        return *this;
    }
};

class PersonJobBuilder : public PersonInfoBuilder
{
public:
    // explicit PersonJobBuilder(Person &person) : PersonInfoBuilder(person) {}
    PersonJobBuilder &works_as(const std::string &position)
    {
        person.position = position;
        return *this;
    }
};

void testInheritanConstructor()
{
    PersonInfoBuilder pb;
    auto person = pb.called("Dmitri")
                      //.work_as("programmer") // will not compile
                      .build();
    std::cout << person;
}
#else

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

template<typename TSelf>
//class PersonJobBuilder : public PersonInfoBuilder<PersonInfoBuilder<TSelf>>
class PersonJobBuilder : public PersonInfoBuilder<TSelf>
{
public:
    // explicit PersonJobBuilder(Person &person) : PersonInfoBuilder(person) {}
    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") // will not compile
                .born_on("01/01/1980")
                .build();
    std::cout << me;
    // printf("test: %s",typeid(me).name());
}
#endif


int main()
{
    PersonBuilder pb;
    std::cout << "hello world!" << std::endl;
    testInheritanConstructor();
    return 0;
}
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计模式是在软件开发中常用的一种编程思想,它提供了一种解决问题的方法论,可以帮助开发者更加灵活和高效地开发软件。基于qt4开源跨平台开发框架的PDF设计模式主要包括以下几个方面。 首先,观察者模式是一种常用的设计模式,它可以用于实现PDF文件的订阅和通知功能。通过该模式,用户可以选择关注自己感兴趣的PDF文件,并在文件更新时接收到通知。 其次,工厂模式是常用的创建型设计模式,它可以帮助开发者根据需要创建不同类型的PDF文件。例如,可以使用工厂模式创建基本的PDF文件、加密的PDF文件或者带有水印的PDF文件。 再次,装饰器模式是一种结构型设计模式,可以用于在不修改现有代码的情况下为PDF文件添加额外的功能。开发者可以通过装饰器模式为PDF文件添加页眉、页脚、书签等功能,同时保持原有的PDF文件结构和功能不受影响。 此外,策略模式也是常用的设计模式之一,在PDF开发中可以用于实现不同的压缩策略和加密策略。通过策略模式,开发者可以根据需求选择不同的策略来实现对PDF文件的处理和管理。 最后,单例模式是一种创建型设计模式,可以确保在整个应用程序中只有一个PDF文件实例。通过单例模式,可以在不同的模块中共享同一个PDF文件对象,避免资源浪费和数据冲突。 总而言之,设计模式在基于qt4开源跨平台开发框架的PDF开发中具有重要的作用。以上提到的几种设计模式可以帮助开发者更好地组织和管理PDF文件,提高开发效率和代码的可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值