设计模式学习笔记

基于

目的

带着问题来学

  • 解决什么问题
  • 如何解决(越具体越好)
  • 学到了什么(语法, 设计, 改造)

c1

ref

引言 |《Design Patterns in Modern C++》 | ZenLian
https://zenlian.github.io/posts/design-pattern-in-modern-cpp/introduction/

小结

  • 学习了几个原则

    SOLID 是以下 5 大设计原则的首字母缩写:
    单一职责原则(Single Responsibility Principle,SRP)
    开闭原则(Open-Closed Principle,OCP)
    里氏替换原则(Liskov Substitution Principle,LSP)
    接口隔离原则(Interface Segregation Principle,ISP)
    依赖倒置原则(Dependency Inversion Principle,DIP)

  • 发现变化, 抽离不变; 实际上和我写代码的思路一样, 只是人家能够表达出来, 总结出来, 还有大量的经验作为栗子; 给我时间我我也一样能总结出来, 不过不会这么完整, 也不会则这么好
  • 使用cpp的特性, 能够简化代码, 实现这些原则

c2 建造者模式 Builder

ref

疑问&小结

提问:
以下的小结如何实现/使用/目的 ?

  • 疑问: 为什么emplace_back 类型不匹配?

    1
    2
    3
    vector<pair<string, string>> attributes;
    attributes.push_back({"src", "http://pokemon.com/pikachu.png"}); // OK
    attributes.emplace_back({"src", "http://pokemon.com/pikachu.png"}); // error
  • 学习了建造者模式写html

  • 使用builder 去创造 obj

  • 使用protect保护构造函数, 禁止手动创建obj

  • 使用operator() 重载类型转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct HtmlBuilder {
    HtmlElement root;
    ...
    operator HtmlElement() const {
    return root;
    }
    ...
    };

  • 流式调用, 早就知道并运用

  • 使用using self = PersonAddressBuilder;简化类内部代码(免得写得好累)

  • emplace_back和push_back

  • 使用unique_ptr<HtmlBuilder> 通过移动构造转移所有权 make_unique<HtmlBuilder>

    1
    2
    3
    static unique_ptr<HtmlBuilder> build(string root_name) {
    return make_unique<HtmlBuilder>(root_name);
    }
  • explicit 关键字

  • initializer_list 模板使用

    1
    2
    3
    4
    5
    6
    7
    struct P : Tag
    {
    explicit P(const string& text)
    : Tag("p", text) {}
    explicit P(initializer_list<Tag> children)
    : Tag("p", chidren) {}
    };

代码

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
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#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 (auto&& i : tag.attributes) {
os << " " << i.first << '=' << i.second;
}

os << ">" << endl << tag.text << endl;
for (auto&& i : tag.children) {
os << i;
}
os << "</" << tag.name << ">" << 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 string& text) : Tag("p", text) {}
explicit P(initializer_list<Tag> children) : Tag("p", children) {}
};

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

int main() {
std::cout << P{IMG{"http://pokemon.com/pikachu.png"}} << std::endl;
return 0;
}

c3 工厂模式Factories

ref

疑问&小结

  • 工厂模式
  • 内部工厂Inner Factory
    • 与上面的区别是,cpp用friend, 而没有friend的只能用inner
  • virtual SingleCore* CreateSingleCore() = 0; 纯虚函数, 无法实例化, 只能作为抽象工厂
  • 工厂和构造函数的区别/好处
    • 可以拒绝, 可以返回nullptr
    • 可以更名,
    • 可以聚合一类对象的创造
  • 与builder的区别, 工厂一次性地创建一个对象, builder分段地创建

    Factory is different from Builder in that, with a Factory, you typically create an object in one go, whereas with Builder, you construct the object piecewise by providing information in parts.

c4 原型模式Prototype

ref

原型模式 |《Design Patterns in Modern C++》 | ZenLian
https://zenlian.github.io/posts/design-pattern-in-modern-cpp/prototype/

reference