一. 备忘录模式

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态

应用场景:

  1. 当你需要创建对象状态快照来恢复其之前的状态时,可以使用备忘录模式
  2. 当直接访问对象的成员变量、获取器或设置器将导致封装被突破时,可以使用该模式

我们来模拟一个例子:在游戏中,人物可以保存自己的血量,并可将血量回溯到上一次保存的血量

#include <cstdio>                                                                                                                                       
#include <memory>

class Monster{
public:
    double HP;
    double Atk;

public:
    explicit Monster(double HP, double Atk)
    :HP(HP), Atk(Atk){}
};

class Memento{
private:
    double HP;

public:
    explicit Memento(double HP)
    :HP(HP){}

public:
    double getHP(void) const{
        return this->HP;
    }
};

class Brave{
private:                                                                                                                                       
    double HP;
    double Atk;

public:
    explicit Brave(double HP, double Atk)
    :HP(HP), Atk(Atk){}

public:
    void fight(Monster &monster){
        while(true){
            if(this->HP <= 0){
                printf("You are dead.\n");
                break;
            }
            if(monster.HP <= 0){
                printf("You wins.\n");
                break;
            }
            this->HP -= monster.Atk;
            monster.HP -= this->Atk;
        }
    }
    
    void show(void) const{
        printf("HP: %.2lf   Atk: %.2lf\n", this->HP, this->Atk);
    }
  
    std::shared_ptr<Memento> saveState(void) const{
        return std::make_shared<Memento>(this->HP);
    }
    
    void restoreState(const std::shared_ptr<Memento> &memento){
        this->HP = memento->getHP();
    }
};

class CareTaker{
private:
    std::shared_ptr<Memento> memento;

public:
    void setMemento(const std::shared_ptr<Memento> &memento){
        this->memento = memento;
    }

    std::shared_ptr<Memento> getMemento(void) const{
        return this->memento;
    }
};

二. 组合模式

组合模式:将对象组合成树形结构以表示 “部分-整体” 的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性

应用场景:

  1. 如果你需要实现树状对象结构,可以使用组合模式
  2. 如果你希望客户端代码以相同方式处理简单和复杂元素,可以使用该模式

我们来模拟一个例子:linux 的文件系统

#include <cstdio>                                                                                                                                       
#include <string>
#include <memory>
#include <list>
#include <algorithm>

class File{
private:
    std::string file_name;

public:
    explicit File(const std::string &file_name)
    :file_name(file_name){}
    
    virtual ~File() = default;

public:
    std::string fileName(void) const{
        return this->file_name;
    }

    virtual void show(int depth) const = 0;
};

class Leaf : public File{
public:
    explicit Leaf(const std::string &file_name)
    :File(file_name){}

public:
    void show(int depth = 1) const override{
        printf("%s%s\n", std::string(depth, '-').c_str(), this->fileName().c_str());
    }
};

class Composite : public File{
private:
    std::list<std::shared_ptr<File>> files;

public:
    explicit Composite(const std::string &file_name)
    :File(file_name){}

public:
    void addLeaf(const std::string &file_name){
        this->files.emplace_back(std::make_shared<Leaf>(file_name));
    }

    std::shared_ptr<Composite> addComposite(const std::string &file_name){
        auto file = std::make_shared<Composite>(file_name);
        this->files.emplace_back(file);
        return file;
    }

    void remove(const std::string &file_name){
        this->files.erase(std::remove_if(
                    this->files.begin(), this->files.end(), 
                    [&file_name](const std::shared_ptr<File> file){ return file->fileName() == file_name; }
                    ));
    } 

    void show(int depth = 1) const override{
        printf("%s%s\n", std::string(depth, '-').c_str(), this->fileName().c_str());
        for(const auto &elem : this->files)
            elem->show(depth + 2);
    }
};

int main(void){
    Composite root("root");
    auto c_plus_plus = root.addComposite("C/C++");
    c_plus_plus->addLeaf("main.cpp");
    c_plus_plus->addLeaf("test.cpp");
    
    auto python = root.addComposite("Python");
    python->addLeaf("main.py");
    python->addLeaf("test.py");
    root.show();
    return 0;
}  

三. 桥接模式

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

应用场景:

  1. 如果你想要拆分或重组一个具有多重功能的庞杂类 (例如能与多个数据库服务器进行交互的类), 可以使用桥接模式
  2. 如果你希望在几个独立维度上扩展一个类, 可使用该模式
  3. 如果你需要在运行时切换不同实现方法, 可使用桥接模式

我们来模拟一个例子:在几何图形的分类中,假设我们有矩形和椭圆之分,这时我们又希望加入颜色(红色、绿色)来扩展它的层级

#include <algorithm>                                                                                                                                    
#include <cstdio>
#include <memory>
#include <string>

class Color{
private:
    std::string color;

public:
    explicit Color(const std::string &color)
    :color(color){}

    virtual ~Color() = default;

public:
    std::string getColor(void) const{
        return this->color;
    }
};

class Red : public Color{
public:
    Red()
    :Color("red"){}
};

class Blue : public Color{
public:
    Blue()
    :Color("blue"){}
};

class Shape{
private:
    std::unique_ptr<Color> color;
    std::string shape;

public:
    explicit Shape(const std::string &shape)
    :color(nullptr), shape(shape){}

    virtual ~Shape() = default;

public:
    void setColor(std::unique_ptr<Color> &&color){
        this->color = std::move(color);
    }
    
    void getShape(void) const{
        if(this->color == nullptr)
            printf("%s\n", this->shape.c_str());
        else
            printf("%s %s\n", this->color->getColor().c_str(), this->shape.c_str());
    }
};

class Rectangle : public Shape{
public:
    Rectangle()
    :Shape("rectangle"){}
};

class Ellipse : public Shape{
public:
    Ellipse()
    :Shape("ellipse"){}
};

int main(void){
    Rectangle rectangle;
    rectangle.getShape();
    
    rectangle.setColor(std::make_unique<Blue>());
    rectangle.getShape();
    
    rectangle.setColor(std::make_unique<Red>());
    rectangle.getShape();
    return 0;
}