设计模式 Design patterns

[toc]

面向对象设计原则

单一职责原则(Single Responsibility Principle)

尽量让每个类只负责软件中的一个功能, 并将该功能完全封装在该类中.

开闭原则(Open/closed Principle)

对于扩展, 类应该是“开放”的;对于修改, 类则应是“封闭”的.

里氏替换原则(Liskov Substitution Principle)

扩展一个类时, 要能在不修改客户端代码的情况下将子类的对象作为父类对象进行传递. 这意味着子类必须保持与父类行为的兼容.

接口隔离原则(Interface Segregation Principle)

客户端不应被强迫依赖于其不使用的方法. 尽量缩小接口的范围, 使得客户端的类不必实现其不需要的行为.

依赖倒置原则(Dependency Inversion Principle)

高层次的类不应该依赖于低层次的类. 两者都应该依赖于抽象接口. 抽象接口不应依赖于具体实现. 具体实现应该依赖于抽象接口.

合成复用原则(Composite Reuse Principle)

尽量使用对象组合,而不是继承来达到复用的目的.

迪米特法则(Law of Demeter)

最少知识原则,一个类应当尽可能少的与其他类发生相互作用.

创建型模式

创建型模式隐藏了类的实例的创建细节, 通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的.

简单工厂:一个工厂, 通过产品类型创建不同产品 工厂方法:每个产品一个工厂 抽象工厂:每个产品族一个工厂

单例模式(Singleton)

保证一个类只有一个实例, 并提供一个访问该实例的全局节点.

单例模式.cpp
// 最简单高效的单例模式模板类
template <typename T>
class singleton_t{
protected:
    singleton_t() = default;
    ~singleton_t() = default;
private:
    singleton_t(const singleton_t &) = delete;
    singleton_t(singleton_t &&) = delete;
    singleton_t& operator=(const singleton_t &) = delete;
    singleton_t& operator=(singleton_t &&) =delete;
public:
    static T& get_instance(){
        static T _instance; // 默认静态变量初始化是线程安全的
        return _instance;
    }
};

namespace {
    class _work_t{
    public:
        void set(std::string name){
            m_name = name;
        }
        std::string& get(){
            return m_name;
        }
    private:
        std::string m_name;
    };
} // namespace 

// 仅导出单例实现
using work_t = singleton_t<_work_t>;

int main(){
    work_t::get_instance().set("1");
    std::cout << work_t::get_instance().get() << std::endl;
}
单例模式.go
package singleton
import "sync"
// Singleton 是单例模式接口,导出的
// 通过该接口可以避免 GetInstance 返回一个包私有类型的指针
type Singleton interface {
    foo()
}

// singleton 是单例模式类,包私有的
type singleton struct{}

func (s singleton) foo() {}

var (
    instance *singleton
    once     sync.Once
)

// GetInstance 用于获取单例模式对象
func GetInstance() Singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

func main(){
    ins1 := GetInstance()
    ins2 := GetInstance()
    if ins1 != ins2 {
        t.Fatal("instance is not equal")
    }
}

工厂方法模式(Factory Method)

在父类中提供一个创建对象的接口以允许子类决定实例化对象的类型.

工厂方法模式
// 抽象工厂类 生产电影
class factory_i {
public:
    virtual std::shared_ptr<movie_t> get_movie() = 0;
};

// 具体工厂类 中国生产者
class chinese_producer_t : public factory_i {
public:
    std::shared_ptr<movie_t> get_movie() override { return std::make_shared<chinese_movie_t>(); }
};

// 抽象产品类 电影
class movie_i {
public:
    virtual std::string get_a_movie() = 0;
};

// 具体产品类 电影::国产电影
class chinese_movie_t : public movie_i {
public:
    std::string get_a_movie() override {
        return "《让子弹飞》";
    }
};

int main() {
    std::shared_ptr<factory_i> factory;
    std::shared_ptr<movie_i> product;
​
    // 选择创建者的类型
    factory = std::make_shared<chinese_producer_t>();

    product = factory->get_movie();
    std::cout << "获取一部电影: " << product->get_a_movie() << std::endl;
}

抽象工厂模式(Abstract Factory)

让你能创建一系列相关的对象, 而无需指定其具体类.

抽象工厂模式
// 抽象工厂类 生产电影和书籍类等
class factory_i {
public:
    virtual std::shared_ptr<movie_i> product_movie() = 0;
    virtual std::shared_ptr<book_i> product_book() = 0;
};

// 具体工厂类 中国生产者
class chinese_producer_t : public factory_i {
public:
    std::shared_ptr<movie_i> product_movie() override {
        return std::make_shared<chinese_movie>();
    }
​
    std::shared_ptr<book_i> product_book() override {
        return std::make_shared<chinese_book>();
    }
};

// 抽象产品类 电影
class movie_i {
public:
    virtual std::string name() = 0;
};
​
// 抽象产品类 书籍
class book_i {
public:
    virtual std::string name() = 0;
};

// 具体产品类 电影::国产电影
class chinese_movie_t : public movie_i {
    std::string name() override {
        return "《让子弹飞》";
    }
};

// 具体产品类 书籍::国产书籍
class chinese_book_t : public book_i {
    std::string name() override {
        return "《三国演义》";
    }
};
​
int main() {
    std::shared_ptr<factory_i> factory;
    // 选择创建者的类型
    factory = std::make_shared<chinese_producer_t>();
    std::shared_ptr<movie_i> movie;
    std::shared_ptr<book_i> book;
    movie = factory->product_movie();
    book = factory->product_book();
    std::cout << "获取一部电影: " << movie->name() << std::endl;
    std::cout << "获取一本书: " << book->name() << std::endl;
}

生成器模式(Builder)

使你能够分步骤创建复杂对象. 该模式允许你使用相同的创建代码生成不同类型和形式的对象.

生成器模式
// 产品类 车
class car_t {
public:
    void set_car_tire(std::string t) {
        m_tire = t;
        std::cout << "set tire: " << tire_ << std::endl;
    }
    void set_car_engine(std::string e) {
        m_engine = e;
        std::cout << "set engine: " << engine_ << std::endl;
    }
private:
    std::string m_tire;    // 轮胎
    std::string m_engine;  // 发动机
};

// 抽象建造者
class car_builder_i {
public:
    // 抽象方法
    virtual void build_tire() = 0;
    virtual void build_engine() = 0;
    car_t get_car() { return m_car; }
protected:
    car_t m_car;
};

// 具体建造者 奔驰
class benz_builder_t : public car_builder_i {
public:
    // 具体实现方法
    void build_tire() override {
        m_car.set_car_tire("benz_tire");
    }
    void build_engine() override {
        car_.set_car_engine("benz_engine");
    }
};

class director_t {
public:​
    void set_builder(car_builder_i *cb) {m_builder = cb;}
    // 组装汽车
    car_t construct_car() {
        m_builder->build_tire();
        m_builder->build_engine();
        return m_builder->get_car();
    }
private:
    car_builder_i* m_builder;
};

int main() {
    // 抽象建造者(一般是动态确定的)
    car_builder_i* builder;
    // 指挥者
    director_t* director = new director_t();
    // 产品
    car_t car;
​
    // 建造奔驰
    std::cout << "==========construct benz car==========" << std::endl;
    builder = new benz_builder_t();
    director->set_builder(builder);
    car = director->construct_car();
    delete builder;

    std::cout << "==========done==========" << std::endl;
    delete director;
}

原型模式(Prototype)

让你能够复制已有对象, 而又无需使代码依赖它们所属的类.

原型模式
// 抽象原型类
class object_i {
public:
    virtual object_i* clone() = 0;
};
​
// 邮件的附件
class attachment_t {
public:
    void set_content(std::string content) {
        m_content = content;
    }
    std::string get_content() {
        return content;
    }​
private:
    std::string m_content;
};

// 具体原型: 邮件类
class email_t : public object_i {
public:
    email_t(){}
    email_t(std::string text, std::string attachment_content) : m_text(text), m_attachment(new attachment_t()) {
        m_attachment->set_content(attachment_content);
    }
    ~email_t() {
        delete m_attachment;
    }

    void display() {
        std::cout << "正文: " << m_text << std::endl
        << "邮件: " << m_attachment->get_content() << std::endl;
    }

    // 深拷贝
    email_t* clone() override {
        return new email_t(this->m_text, this->m_attachment->get_content());
    }

    void set_text(std::string new_text) {
        m_text = new_text;
    }
    void set_attachment(std::string content) {
        m_attachment->set_content(content);
    }
private:
    std::string m_text;
    attachment_t *m_attachment;
};

int main() {
    email_t* email = new email_t("最初的文案", "最初的附件");

    email_t* copy_email = email->clone();
    copy_email->set_text("新文案");
    copy_email->set_attachment("新附件");

    std::cout << "original email:" << std::endl;
    email->display();
    std::cout << "copy email:" << std::endl;
    copy_email->display();
    delete email;
    delete copy_email;
}

结构型模式

结构型模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构, 就像搭积木, 可以通过简单积木的组合形成复杂的、功能更为强大的结构.

结构型模式可以分为类结构型模式和对象结构型模式:

  • 类结构型模式:关心类的组合, 由多个类可以组合成一个更大的系统, 在类结构型模式中一般只存在继承关系和实现关系.
  • 对象结构型模式:关心类与对象的组合, 通过关联关系使得在一 个类中定义另一个类的实例对象, 然后通过该对象调用其方法.

根据“合成复用原则”, 在系统中尽量使用关联关系来替代继承关系, 因此大部分结构型模式都是对象结构型模式.

适配器模式(Adapter)

让接口不兼容的对象能够相互合作.

适配器模式
// 客户端接口
class target_i {
public:
  virtual ~target_t() = default;
  virtual std::string request() const {
    return "default target's behavior.";
  }
};
// 适配者
class adaptee_t {
public:
  std::string specific_request() const {
    return ".eetpadA eht fo roivaheb laiceps";
  }
};
// 适配器
class adapter_t : public target_i {
public:
  adapter_t(adaptee_t* adaptee) : adaptee_t(adaptee) {}
  std::string request() const override {
    std::string to_reverse = this->adaptee_->specific_request();
    std::reverse(to_reverse.begin(), to_reverse.end());
    return "adapter: (TRANSLATED) " + to_reverse;
  }
private:
  adaptee_t* m_adaptee;
};
// 客户端方法
void client_code(const target_i* target) {
  std::cout << target->request() << std::endl;
}

int main() {
  target_i* target = new target_i();
  client_code(target);

  adaptee_t* adaptee = new adaptee_t();
  adaptee->specific_request();

  adapter_t* adapter = new adapter_t(adaptee);
  client_code(adapter);

  delete target;
  delete adaptee;
  delete adapter;
}

桥接模式(Bridge)

可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用.

桥接模式
// 抽象类
class pen_i {
public:
    virtual void draw(std::string name) = 0;
    void set_color(color_t* color) {
        m_color = color;
    }
​protected:
    color_t* m_color;
};
// 实现类
class big_pen_t : public pen_i {
public:
    void draw(std::string name) {
        std::string pen_type = "大号钢笔绘制";
        m_color->bepaint(pen_type, name);
    }
};
// 抽象类
class color_i {
public:
    virtual void bepaint(std::string pen_type, std::string name) = 0;
};
// 实现类
class red_t : public color_i {
public:
    void bepaint(std::string pen_type, std::string name) override {
        std::cout << pen_type << "红色的" << name << "." << std::endl;
    }
};

int main() {
    color_i* color = new red_t();
    pen_i* pen = new big_pen_t();
​
    pen->set_color(color);
    pen->draw("太阳");
​
    delete color;
    delete pen;
}

组合模式(Composite)

你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们.

组合模式
// 抽象基类声明组合中的通用操作
class graphic_i {
public:
    virtual void move(int x, int y) = 0;
    virtual void draw() = 0;
};
// 点
class dot_t : public graphic_i {
public:
    dot_t(int x, int y) : m_x(x), m_y(y) {}
    void move(int x, int y) override {
        m_x += x; m_y += y;
    }
    void draw() override {
        printf("在(%d,%d)处绘制点\n", m_x, m_y);
    }
private:
    int m_x,m_y;
};
// 圆
class circle_t : public graphic_i {
public:
    explicit circle_t(int r, int x, int y) : m_radius(r), m_x(x), m_y(y) {}
    void move(int x, int y) override {
        m_x += x; m_y += y;
    }
    void draw() override {
        printf("以(%d,%d)为圆心绘制半径为%d的圆\n",m_x,m_y,m_radius);
    }
​private:
    int m_x,m_y,m_radius;
};
// 组件操作
class graphic_cp : public graphic_i {
public:
    void add(int id, graphic_i* child) {
        m_map[id] = child;
    }
    void remove(int id) {
        m_map.erase(id);
    }
    void move(int x, int y) override {
        for (auto [k,v] : m_map){
            v->move(x, y);
        }
    }
    void draw() override {
        for (auto [k,v] : m_map){
            v->draw(x, y);
        }
    }
​private:
    // key是图表id, value是图表指针
    std::map<int, graphic_i*> m_map;
};


int main() {
    // 组合图
    graphic_cp* all = new graphic_cp();
​
    // 添加子图
    dot_t* dot1 = new dot_t(1, 2);
    circle_t *circle = new circle_t(5, 2, 2);
    graphic_cp* child_graph = new graphic_cp();
    dot_t* dot2 = new dot_t(4, 7);
    dot_t* dot3 = new dot_t(3, 2);
    child_graph->add(0, dot2);
    child_graph->add(1, dot3);
​
    // 将所有图添加到组合图中
    all->add(0, dot1);
    all->add(1, circle);
    all->add(2, child_graph);
    // 绘制
    all->draw();
​
    delete all;
    delete dot1;
    delete dot2;
    delete dot3;
    delete circle;
}

装饰模式(Decorator)

允许你将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为.

装饰模式
// 具体组件和装饰类的共同基类
class data_source_i {
public:
    virtual void write(std::string data) = 0;
};
// 具体组件
​class file_source_t : public data_source_i {
public:
    explicit file_source_t(std::string file_name) : m_fname(file_name) {}
    void write(std::string data) override {
        printf("写入文件%s中: %s\n", m_fname.c_str(), data.c_str());
    }
​private:
    std::string m_fname;
};
// 装饰类
class data_source_decorator_cp : public data_source_i {
public:
    explicit data_source_decorator_cp(data_source_i* ds) : m_ds(ds) {}
    void write(std::string data) override {
        m_ds->write(data);
    }
​protected:
    data_source_i* m_ds;  // component
};
// 加密装饰器
class encryption_decorator_op : public data_source_decorator_cp {
public:
    using data_source_decorator_cp::data_source_decorator_cp;
    void write(std::string data) override {
        data = "已加密(" + data + ")";
        m_ds->write(data);
    }
};
// 压缩装饰器
class compression_decorator_op : public data_source_decorator_cp {
public:
    using data_source_decorator_cp::data_source_decorator_cp;
    void write(std::string data) override {
        data = "已压缩(" + data + ")";
        m_ds->write(data);
    }
};

int main() {
    file_source_t* source1 = new file_source_t("stdout");
    // 将明码数据写入目标文件
    source1->write("testdata");
​
    // 将压缩数据写入目标文件
    compression_decorator_op* source2 = new compression_decorator_op(source1);
    source2->write("testdata");
​
    // 将压缩且加密数据写入目标文件
    encryption_decorator_op* source3 = new encryption_decorator_op(source2);
    source3->write("testdata");
​
    delete source1;
    delete source2;
    delete source3;
}

外观模式(Facade)

能为程序库、框架或其他复杂类提供一个简单的接口.

外观模式
class computer_t {
public:
    computer_t() {
        m_mem = new memory_t();
        m_proc = new processor_t();
        m_hd = new hard_disk_t();
        m_os = new os_t();
    }
    ~computer_t() {
        delete m_mem;
        delete m_proc;
        delete m_hd;
        delete m_os;
        m_mem = nullptr;
        m_proc = nullptr;
        m_hd = nullptr;
        m_os = nullptr;
    }
​
    void power_on() {
        std::cout << "正在开机..." << std::endl;
        m_mem->self_check();
        m_proc->run();
        m_hd->read();
        m_os->load();
        std::cout << "开机成功!" << std::endl;
    }
​private:
    memory_t* m_mem;
    processor_t* m_proc;
    hard_disk_t* m_hd;
    os_t* m_os;
};

// 内存
class memory_t {
public:
    void self_check() {
        std::cout << "内存自检中..." << std::endl;
        std::cout << "内存自检完成!" << std::endl;
    }
};
​
// 处理器
class processor_t {
public:
    void run() {
        std::cout << "启动CPU中..." << std::endl;
        std::cout << "启动CPU成功!" << std::endl;
    }
};
​
// 硬盘
class hard_disk_t {
public:
    void read() {
        std::cout << "读取硬盘中..." << std::endl;
        std::cout << "读取硬盘成功!" << std::endl;
    }
};
​
// 操作系统
class os_t {
public:
    void load() {
        std::cout << "载入操作系统中..." << std::endl;
        std::cout << "载入操作系统成功!" << std::endl;
    }
};

int main() {
    computer_t* c = new computer_t();
    c->power_on();
    delete c;
}

享元模式(Flyweight)

摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在优先的内存容量中载入更多对象.

享元模式
// 享元类 树木类型是固定的可以通过指针共享给大量树
class tree_type_t {
public:
    tree_type_t(std::string n, std::string c, std::string t) :
        m_name(n), m_color(c), m_texture(t) {}
    void draw(std::string canvas, double x, double y) {
        // 创建特定类型、颜色和纹理的位图
        // 在画布坐标(x,y)处绘制位图
    }
​private:
    std::string m_name;
    std::string m_color;
    std::string m_texture;
};

// 享者 坐标随机独有, 但引用树的类型数据会大量重复
class tree_t {
public:
    tree_t(double x, double y, tree_type_t* t) : m_x(x), m_y(y), m_t(t) {}
    void draw(std::string canvas) {
        return m_t->draw(canvas, m_x, m_y);
    }
​private:
    double m_x;
    double m_y;
    tree_type_t* m_t;
};

// 享元工厂: 共享数据缓存, 应该是单例类
namespace detail_ns{
class tree_factory_t {
public:
    tree_type_t* get_tree_type(std::string name, std::string color, std::string texture) {
        std::string key = name + "_" + color + "_" + texture;
        auto iter = mp_tree_type.find(key);
        if (iter == mp_tree_type.end()) {
            // 新的tree type
            tree_type_t* new_tree_type = new tree_type_t(name, color, texture);
            mp_tree_type[key] = new_tree_type;
            return new_tree_type;
        } else {
            // 已存在的tree type
            return iter->second;
        }
    }
​private:
    // 共享池, 其中key格式为name_color_texture
    std::map<std::string, tree_type_t*> mp_tree_type;
};
} // namespace detail_ns
// 包装为单例类(见模板单例类)
using tree_factory_t = singleton_t<detail_ns::tree_factory_t>;

// forest_t包含数量及其庞大的tree_t
class forest_t {
public:
    void plan_tree(double x, double y, std::string name, std::string color, std::string texture) {
        tree_type_t* type = tree_factory_t::get_instance().get_tree_type(name, color, texture);
        tree_t tree = tree_t(x, y, type);
        m_trees.push_back(tree);
    }
    void draw() {
        for (auto tree : m_trees) {
            tree.draw("canvas");
        }
    }
​private:
    std::vector<tree_t> m_trees;
};

int main() {
    forest_t* forest = new forest_t();
    // 在forest中种植很多棵树
    for (int i = 0; i < 500; i++) {
        for (int j = 0; j < 500; j++) {
            double x = i;
            double y = j;
            // 树类型1: 红色的杉树
            forest->plan_tree(x, y, "杉树", "红色", "");
            // 树类型2: 绿色的榕树
            forest->plan_tree(x, y, "榕树", "绿色", "");
            // 树类型3: 白色的桦树
            forest->plan_tree(x, y, "桦树", "白色", "");
        }
    }
    forest->draw();
    delete forest;
}

代理模式(Proxy)

让你能够提供对象的替代品或其占位符. 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理.

代理模式
// 远程服务接口
class video_lib_i {
public:
    virtual std::string get_video_list() = 0;//略缩图列表
    virtual std::string get_video_info(int id) = 0;//视频页面
};
// 服务类(请求)
class pull_video_t : public video_lib_i {
public:
    std::string get_video_list() override {
        // 向远程视频后端服务发送一个API请求
        return "video list";
    }
​
    std::string get_video_info(int id) override {
        // 向远程视频后端服务发送一个API请求
        return "video info";
    }
};
// 代理类(缓存)
​class video_cache_t : public video_lib_i {
public:
    explicit video_cache_t(video_lib_i* service) : mp_service(service), m_need_reset(false), m_list_cache(""), m_video_cache("") {}

    void reset() {
        m_need_reset = true;
    }
​
    std::string get_video_list() override {
        if (m_list_cache == "" || m_need_reset) {
            m_list_cache = mp_service->get_video_list();
        }
        return m_list_cache;
    }
​
    std::string get_video_info(int id) override {
        if (m_video_cache == "" || m_need_reset) {
            m_video_cache = mp_service->get_video_info(id);
        }
        return m_video_cache;
    }
​private:
    video_lib_i* mp_service;
    std::string m_list_cache;
    std::string m_video_cache;
    bool m_need_reset;
};

// 管理代理类(渲染)
class video_manager_t {
public:
    explicit video_manager_t(video_lib_i* s) : mp_service(s) {}
    void render_video_page(int id) {
        std::string video_info = mp_service->get_video_info(id);
        // 渲染视频页面, 这里忽略实现
        printf("渲染视频页面: %s\n", video_info.c_str());
    }
    void render_list_panel() {
        std::string video_list = mp_service->get_video_list();
        // 渲染视频缩略图列表, 这里忽略实现
        printf("渲染视频缩略图列表: %s\n", videos.c_str());
    }
​private:
    video_lib_i* mp_service;
};

int main() {
    pull_video_t* p_service = new pull_video_t();
    video_cache_t* p_cache_proxy = new video_cache_t(p_service);
    video_manager_t* p_manager = new video_manager_t(p_cache_proxy);
​
    p_manager->render_video_page(1);
    p_manager->render_list_panel();
​
    delete p_service;
    delete p_cache_proxy;
    delete p_manager;
}

行为型模式

行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化. 行为型模式不仅仅关注类和对象的结构, 而且重点关注它们之间的相互作用.

行为型模式分为类行为型模式和对象行为型模式两种:

  • 类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为, 类行为型模式主要通过多态等方式来分配父类与子类的职责.
  • 对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为, 对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责. 根据“合成复用原则”, 系统中要尽量使用关联关系来取代继承关系, 因此大部分行为型设计模式都属于对象行为型设计模式.

责任链模式(Chain of Responsibility)

允许你将请求沿着处理者链进行发送. 收到请求后, 每个处理者可对请求进行处理, 或将其传递给链上的下个处理者.

责任链模式
// 员工申请处理票据需要上报给上级, 如果上级无权处理就上报给更高的上级
// 抽象处理者
class handler_i {
public:
    // 添加上级
    virtual void set_superior(handler_i* superior) = 0;
    // 处理票据申请, 参数是票据面额
    virtual void handle_request(double amount) = 0;
};

class base_handler_t : public handler_i {
public:
    base_handler_t(double mpa, std::string n) : m_max_processible_amount(mpa), m_name(n), mp_superior(nullptr) {}
    // 设置上级
    void set_superior(handler_i* superior) override {
        m_superior = superior;
    }
    // 处理票据
    void handle_request(double amount) {
        // 可处理时直接处理即可
        if (amount <= m_max_processible_amount) {
            printf("%s处理了该票据, 票据面额:%f\n", m_name.c_str(), amount);
            return;
        }
        // 无法处理时移交给上级
        if (mp_superior != nullptr) {
            printf("%s无权处理, 转交上级...\n", m_name.c_str());
            mp_superior->handle_request(amount);
            return;
        }
        // 最上级依然无法处理时报错
        printf("无人有权限处理该票据, 票据金额:%f\n", m_name.c_str(), amount);
    }
​private:
    double m_max_processible_amount;  // 可处理的最大面额
    std::string m_name;
    handler_i* mp_superior;
};

// 具体处理者: 组长(仅处理面额<=10的票据)
class group_leader_t : public base_handler_t {
public:
    explicit group_leader_t(std::string name) : base_handler_t(10, name) {}
};
​
// 具体处理者: 经理(仅处理面额<=100的票据)
class manager_t : public base_handler_t {
public:
    explicit manager_t(std::string name) : base_handler_t(100, name) {}
};
​
​
// 具体处理者: 老板(仅处理面额<=1000的票据)
class boss_t : public base_handler_t {
public:
    explicit boss_t(std::string name) : base_handler_t(1000, name) {}
};
​
int main() {
    // 请求处理者: 组长、经理和老板
    group_leader_t* p_group_leader = new group_leader_t("张组长");
    manager_t* p_manager = new manager_t("王经理");
    boss_t* p_boss = new boss_t("李老板");
​
    // 设置上级
    p_group_leader->set_superior(p_manager);
    p_manager->setSuperior(p_boss);
​
    // 不同面额的票据统一先交给组长审批(
    p_group_leader->handle_request(8);
    p_group_leader->handle_request(88);
    p_group_leader->handle_request(888);
    p_group_leader->handle_request(8888);
​
    delete p_group_leader;
    delete p_manager;
    delete p_boss;
}

命令模式(Command)

它可将请求转换为一个包含与请求相关的所有信息的独立对象. 该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中, 且能实现可撤销操作.

命令模式
// 用遥控器(Controller)控制电视(TV)

// 命令接口
class command_t {
public:
    virtual void execute() = 0;
};

// 触发者: 遥控器
class controller_t{
public:
    // 设置命令
    void set_command(std::shared_ptr<command_t> cmd) {
        m_cmd = cmd;
    }
    // 执行命令
    void execute_command() {
        m_cmd->execute();
    }
​private:
    std::shared_ptr<command_t> m_cmd;
};

​// 具体命令类: 打开电视
class cmd_tv_open_t : public command_t{
public:
    explicit cmd_tv_open_t(std::shared_ptr<tv_t> tv) : m_tv(tv) {}
    void execute() override {
        tv_->open();
    }
​private:
    std::shared_ptr<tv_t> m_tv;
};

// 接受者: 电视
class tv_t{
public:
    void open() {
        std::cout << "打开电视机!" << std::endl;
    }
};

int main() {
    std::shared_ptr<tv_t> tv = std::make_shared<tv_t>();

    std::shared_ptr<controller_t> controller = std::make_shared<controller_t>();

    std::shared_ptr<command_t> open_cmd = std::make_shared<cmd_tv_open_t>(tv);
​
    controller->setCommand(open_cmd);
    controller->executeCommand();
}

迭代器模式(Iterator)

让你能在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素.

迭代器模式
// 抽象迭代器
class tv_iterator_i{
public:
    virtual void set_channel(int i) = 0;
    virtual void next() = 0;
    virtual void prev() = 0;
    virtual bool is_end() = 0;
    virtual std::string cur() = 0;
    virtual bool is_begin() = 0;
};
​
// 具体迭代器
class abc_iter_t : public tv_iterator_i{
public:
    explicit abc_iter_t(std::vector<std::string> &tvs) : m_tvs(tvs) {}
    void next() override {
        if (m_cur < m_tvs.size()) {
            m_cur++;
        }
    }
    void prev() override {
        if (m_cur > 0) {
            m_cur--;
        }
    }
    void set_channel(int i) override {
        m_cur = i;
    }
    std::string cur() override {
        return m_tvs[m_cur];
    }
    bool is_end() override {
        return m_cur == m_tvs.size();
    }
    bool is_begin() override {
        return m_cur == 0;
    }
​private:
    std::vector<std::string> &m_tvs;
    int m_cur = 0;
};

// 抽象电视机
class tv_i {
public:
    virtual std::shared_ptr<tv_iterator_i> create_iterator() = 0;
};

// 具体电视机
class abc_tv_t : public tv_i {
public:
    std::shared_ptr<tv_iterator_i> create_iterator() override{
        return std::make_shared<abc_iter_t>(m_tvs);
    }
    void add(std::string item) {
        m_tvs.push_back(item);
    }
private:
    std::vector<std::string> m_tvs;
};

int main() {
    abc_tv_t abc;
    abc.add("CCTV-1");
    abc.add("CCTV-2");
    abc.add("CCTV-3");
    abc.add("CCTV-4");
    abc.add("CCTV-5");
​
    auto iter = abc.create_iterator();
    while (!iter->is_end()) {
        std::cout << iter->cur() << std::endl;
        iter->next();
    }
}

中介者模式(Mediator)

能让你减少对象之间混乱无序的依赖关系. 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作.

中介者模式
enum person_e {
    unknown,
    landlord,
    tenant,
};
// 组件基类
class colleague_i {
public:
    void set_mediator(mediator_t *m) {
        mp_mediator = m;
    }
    mediator_t* get_mediator() {
        return mp_mediator;
    }
    void set_person_type(person_e pt) {
        me_person_type = pt;
    }
    person_e get_person_type() {
        return me_person_type;
    }
    virtual void ask()=0;
    virtual void answer()=0;
private:
    mediator_t* mp_mediator;
    person_e me_person_type;
};
​
// 具体组件1: 房东
class landlord_t : public colleague_i {
public:
    landlord_t() {
        m_name = "unknown";
        m_price = -1;
        m_address = "unknown";
        m_phone_number = "unknown";
        set_person_type(person_e::unknown);
    }
    landlord_t(std::string name, int price, std::string address, std::string phone_number) {
        m_name = name;
        m_price = price;
        m_address = address;
        m_phone_number = phone_number;
        set_person_type(person_e::landlord);
    }
    void answer() override {
        printf("房东姓名:%s 房租:%d 地址:%s 电话:%s\n", m_name.c_str(), m_price, m_address.c_str(), m_phone_number.c_str());
    }
    void ask() override {
        printf("房东%s查看租客信息: \n", m_name.c_str());
        this->get_mediator()->operation(this);
    }
private:
    std::string m_name;
    int m_price;
    std::string m_address;
    std::string m_phone_number;
};
​
// 具体组件2: 租客
class tenant_t : public colleague_i {
public:
    tenant_t():m_name("unknown") {}
    explicit tenant_t(std::string name) {
        m_name = name;
        set_person_type(person_e::tenant);
    }
    void ask() {
        printf("租客%s询问房东信息:\n", m_name.c_str());
        this->get_mediator()->operation(this);
    }
    void answer() {
        printf("租客姓名: %s\n", m_name.c_str());
    }
private:
    std::string m_name;
};

// 抽象中介者
class mediator_i {
public:
    // 声明抽象方法
    virtual void register_method(colleague_i*) = 0;
    // 声明抽象方法
    virtual void operation(colleague_i*) = 0;
};

// 具体中介类: 房产中介
class agency_t : public mediator_i {
public:
    void register_method(colleague_i* person) override {
        switch (person->get_person_type()) {
            case person_e::landlord:
                m_landlords.push_back(reinterpret_cast<landlord_t*>(person));
                break;
            case person_e::tenant:
                m_tenants.push_back(reinterpret_cast<tenant_t*>(person));
                break;
            default:
                printf("wrong person\n");
        }
    }
​
    void operation(colleague_i* person) {
        switch (person->get_person_type()) {
            case person_e::landlord:
                for (auto iter : m_tenants){
                    iter->answer();
                }
                break;
            case person_e::tenant:
                for (auto iter : m_landlords){
                    iter->answer();
                }
                break;
            default:
                break;
        }
    }
​
private:
    std::vector<landlord_t*> m_landlords;
    std::vector<tenant_t*> m_tenants;
};

int main() {
    // 房产中介
    agency_t* p_mediator = new agency_t();
​
    landlord_t *p_l1 = new landlord_t("张三", 1820, "天津", "1333");
    tenant_t *p_t1 = new tenant_t("Zhang");
    p_mediator->register_method(p_l1);
​    p_mediator->register_method(p_t1);
    l1->set_mediator(p_mediator);
    t1->set_mediator(p_mediator);

    // 业务逻辑
    t1->ask();
    std::cout << std::endl;
    l1->ask();
​
    delete p_mediator;
    delete p_l1;
    delete p_t1;
}

备忘录模式(Memento)

允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态.

备忘录模式
// 备忘录类保存编辑器的过往状态
class snapshot_t {
public:
    snapshot_t(std::string text, int x, int y, double width)
        : m_text(text), m_cur_x(x), m_cur_y(y), m_selection_width(width) {}
    std::string& get_text() {
        return m_text;
    }
    int get_cur_x() {
        return m_cur_x;
    }
    int get_cur_y() {
        return m_cur_y;
    }
    double get_selection_width() {
        return m_selection_width;
    }
private:
    const std::string m_text;
    const int m_cur_x;
    const int m_cur_y;
    const double m_selection_width;
};
​
// 原发器中包含了一些可能会随时间变化的重要数据
// 它还定义了在备忘录中保存自身状态的方法, 以及从备忘录中恢复状态的方法
class editor_t {
public:
    void set_text(std::string text) {
        m_text = text;
    }
    void set_cursor(int x, int y) {
        m_cur_x = x;
        m_cur_y = y;
    }
    void set_selection_width(double width) {
        m_selection_width = width;
    }
    // 在备忘录中保存当前的状态
    std::shared_ptr<snapshot_t> create_snapshot() {
        // 备忘录是不可变的对象, 因此原发器会将自身状态作为参数传递给备忘录的构造函数
        auto res = std::make_shared<snapshot_t>(m_text, m_cur_x, m_cur_y, m_selection_width);
        printf("创建编辑器快照成功, text:%s x:%d y:%d width:%.2f\n",
         m_text.c_str(), m_cur_x, m_cur_y, m_selection_width);
        return res;
    }
    void resotre(std::shared_ptr<snapshot_t> p_snapshot) {
        m_text = p_snapshot->get_text();
        m_cur_x = p_snapshot->get_cur_x();
        m_cur_y = p_snapshot->get_cur_y();
        m_selection_width = p_snapshot->get_selection_width();
        printf("恢复编辑器状态成功, text:%s x:%d y:%d width:%.2f\n",
         m_text.c_str(), m_cur_x, m_cur_y, m_selection_width);
    }
private:
    // 文本
    std::string m_text;
    // 光标位置
    int m_cur_x;
    int m_cur_y;
    // 当前滚动条位置
    double m_selection_width;
};

class command_t {
public:
    explicit command_t(editor_t* e) : mp_editor(e) {}
    void make_backup() {
        mp_backup = mp_editor->create_snapshot();
    }
    void undo() {
        if (mp_backup) {
            mp_editor->resotre(mp_backup);
        }
    }
​private:
    editor_t* mp_editor;
    std::shared_ptr<snapshot_t> mp_backup;
};

int main() {
    // 创建原发器和负责人
    editor_t editor;
    command_t command(&editor);
​
    // 定义初始状态
    editor.set_text("text1");
    editor.set_cursor(21, 34);
    editor.set_selection_width(3.4);
​
    // 保存状态
    command.make_backup();
​
    // 更改编辑器状态
    editor.set_text("text2");
    editor.set_cursor(111, 222);
    editor.set_selection_width(111.222);
​
    // 撤销
    command.undo();
}

观察者模式(Observer)

允许你定义一种订阅机制, 可在对象事件发生时通知多个“观察”该对象的其他对象.

观察者模式
// 抽象观察者
class observer_i {
public:
    virtual void response() = 0;
};
​
// 具体观察者: 狗
class dog_t : public observer_i {
public:
    void response() override {
        std::cout << "狗追猫" << std::endl;
    }
};
​

class cat_t {
public:
    // 注册观察者
    void attach(observer_i* observer) {
        m_observers.push_back(observer);
    }
    // 注销观察者
    void detach(observer_i* observer) {
        for(auto iter : m_observers){
            if (*it == observer) {
                m_observers.erase(it);
                break;
            }
        }
    }
    void cry() {
        std::cout << "猫叫!" << std::endl;
        for (auto ob : m_observers) {
            ob->response();
        }
    }
​private:
    std::vector<observer_i*> m_observers;
};

int main() {
    // 发布者
    cat_t cat;
    // 观察者
    dog_t dog;
    // 添加订阅关系
    cat.attach(&dog);
    // 发布消息
    cat.cry();
}

状态模式(State)

让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样.

状态模式
// 论坛账号
class forum_account_t {
public:
    explicit forum_account_t(std::string name):m_name(name),mp_state(std::make_shared<PrimaryState>(this)){};
    void set_state(std::shared_ptr<state_i> state) {
        mp_state = state;
    }
    std::shared_ptr<state_i> get_state() {
        return mp_state;
    }
    std::string& get_name() {
        return m_name;
    }
    void download_file(int score){
        mp_state->download_file(score);
    }
    void write_note(int score){
        mp_state->write_note(score);
    }
    void reply_note(int score){
        mp_state->write_note(score);
    }
​private:
    std::shared_ptr<state_i> mp_state;
    std::string m_name;
};

// 等级状态
class state_i {
public:
    virtual void check_state() = 0;
​
    void set_point(int point) {
        point_ = point;
    }
    int get_point() {
        return point_;
    }
    void set_state_name(std::string name) {
        m_state_name = name;
    }
    std::string get_state_name() {
        return m_state_name;
    }
    forum_account_t* get_account() {
        return mp_account;
    }
​
    virtual void download_file(int score) {
        m_point -= score;
        check_state();
    }
​
    virtual void write_note(int score) {
        m_point += score;
        check_state();
    }
​
    virtual void reply_note(int score) {
        m_point += score;
        check_state();
    }
​protected:
    forum_account_t* mp_account;
    int m_point;
    std::string m_state_name;
};
​
// 具体状态类: 新手
class primary_state_t : public state_i {
public:
    explicit primary_state_t(state_i* state) {
        mp_account = state->get_account();
        m_point = state->get_point();
        m_state_name = "新手";
    }
    explicit primary_state_t(forum_account_t *account) {
        mp_account = account;
        m_point = 0;
        m_state_name = "新手";
    }
    void download_file(int score) override {
        printf("对不起, %s没有下载文件的权限!\n", mp_account->get_name().c_str());
    }
    void check_state() override{
        if (m_point >= 1000){
            mp_account->set_state(std::make_shared<high_state_t>(this));
        }
        else if (m_point >= 100){
            mp_account->set_state(std::make_shared<middle_state_t>(this));
        }
    };
};
// 具体状态类: 高手
// 具体状态类: 专家

​int main() {
    forum_account_t account("test");
    account.write_note(20);
    account.download_file(20);
    account.reply_note(100);
}

策略模式(Strategy)

能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换.

策略模式
// 抽象策略类: 排序
class sort_i {
public:
    virtual void sort_vector(std::vector<int> &arr) = 0;
};

// 具体策略类: 冒泡排序
class bubble_sort_t : public sort_i {
public:
    void sort_vector(std::vector<int> &vi) override {
        // sort
    }
};

class array_handler_t {
public:
    void sort_vector(std::vector<int> &arr) {
        return mp_sort->sort_vector(arr);
    }
    void set_sort_strategy(sort_i* sort) {
        mp_sort = sort;
    }
​private:
    sort_i* mp_sort;
};

int main() {
    std::vector<int> arr;
    array_handler_t ah;
    bubble_sort_t* p_bs = new bubble_sort_t();

    ah.set_sort_strategy(p_bs);
    ah.sort_vector(arr);
    delete p_bs;
}

模板方法模式(Template Method)

在超类中定义一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤.

模板方法模式
// 抽象类: 银行业务办理流程
class bank_op_i {
public:
    void take_number() {
        std::cout << "排队取号. " << std::endl;
    }
    virtual void transact() = 0;
    void evalute() {
        std::cout << "反馈评分. " << std::endl;
    }
    void process() {
        take_number();
        transact();
        evalute();
    }
};

// 具体类: 存款
class deposit_t : public bank_op_i {
public:
    void transact() override {
        std::cout << "存款..." << std::endl;
    }
};
​
// 具体类: 取款
class withdraw_t : public bank_op_i {
public:
    void transact() override {
        std::cout << "取款..." << std::endl;
    }
};
​
// 具体类: 转账
class transfer_t : public bank_op_i {
public:
    void transact() override {
        std::cout << "转账..." << std::endl;
    }
};

int main() {
    // 存款
    bank_op_i* deposit = new deposit_t();
    deposit->process();
    delete deposit;
​
    // 取款
    bank_op_i* withdraw = new withdraw_t();
    withdraw->process();
    delete withdraw;
​
    // 转账
    bank_op_i* transfer = new transfer_t();
    transfer->process();
    delete transfer;
}

访问者模式(Vistor)

将算法与其所作用的对象隔离开来.

访问者模式
// 抽象访问者
class vistor_i {
public:
    void set_name(std::string name) {
        m_name = name;
    }
    virtual void visit(apple_t *apple) = 0;
    virtual void visit(book_t *book) = 0;
protected:
    std::string m_name;
};

// 具体访问者类: 顾客
class customer_t : public vistor_i {
public:
    void visit(apple_t *apple) {
        std::cout << "顾客" << m_name << "挑选苹果. " << std::endl;
    }
​
    void visit(book_t *book) {
        std::cout << "顾客" << m_name << "买书. " << std::endl;
    }
};
​
// 具体访问者类: 收银员
class saler_t : public vistor_i {
public:
    void visit(apple_t *apple) {
        std::cout << "收银员" << m_name << "给苹果过称, 然后计算价格. " << std::endl;
    }
​
    void visit(book_t *book) {
        std::cout << "收银员" << m_name << "计算书的价格. " << std::endl;
    }
};

// 抽象元素类
class product_i {
public:
    virtual void accept(vistor_i *vistor) = 0;
};
// 具体产品类: 苹果
class apple_t : public product_i {
public:
    void accept(vistor_i *vistor) override {
        vistor->visit(this);
    }
};
// 具体产品类: 书籍
class book_t : public product_i {
public:
    void accept(vistor_i *vistor) override {
        vistor->visit(this);
    }
};
​// 购物车
class shopping_cart_t {
public:
    void accept(vistor_i *vistor) {
        for (auto prd : m_product_list) {
            prd->accept(vistor);
        }
    }
    void add_product(product_i *product) {
        m_product_list.push_back(product);
    }
    void remove_product(product_i *product) {
        m_product_list.remove(product);
    }
​private:
    std::list<product_i*> m_product_list;
};

int main() {
    book_t book;
    apple_t apple;
    shopping_cart_t basket;
​
    basket.add_product(&book);
    basket.add_product(&apple);
​
    customer_t customer;
    customer.set_name("小张");
    basket.accept(&customer);
​
    saler_t saler;
    saler.set_name("小杨");
    basket.accept(&saler);
}

模板编程特殊设计模式

奇异递归模板模式(Curiously Recurring Template Pattern)

CRTP 的主要作用往往是基类需要获取一些派生类信息,或许是成员,或许是方法,或许是类型本身,再通过在基类中实现方法继承来扩展派生类本身,而且可以避免虚函数、动态分派带来的额外运行时代价的问题。比如 std::enable_shared_from_this 就是获取派生类类型本身来给派生类生成 shared_from_this 方法;而 boost::less_than_comparable 就是获取一个派生类方法 operator< 来给派生类生成其它的比较运算符。

奇异递归模板模式
template <template <typename ...> class ...base_i>
struct cat_cp: public base_i<cat_cp<base_i...>>... {
  cat_cp(std::string name)
      : m_name{std::move(name)}, base_i<cat_cp<base_i...>>{*this}... {
  }
    std::string m_name;
};

template <typename derive_tn>
struct eat_op {
  eat_op(const derive_tn &self)
      : m_self{self} {
  }
  void eat() {
    std::cout << m_self.m_name << " eat!"<<std::endl;
  }
  const derive_tn &m_self;
};

template <typename derive_tn>
struct sleep_op {
  sleep_op(const derive_tn &self)
      : m_self{self} {
  }
  void sleep() {
    std::cout << m_self.m_name << " sleep!"<<std::endl;
  }
  const derive_tn &m_self;
};

int main() {
  cat_cp<eat_op,sleep_op> cat1("cat1");
  cat1.eat();
  cat1.sleep();
}

扩展

awesome-design-patterns C++ CRTP简介

guobao.v@gmail.com all right reserved,powered by Gitbook最后编辑时间: 2022-11-30 03:13:24

results matching ""

    No results matching ""