一. 责任链模式

责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

应用场景:

  1. 当程序需要使用不同方式处理不同种类请求,而且请求类型和顺序预先未知时,可以使用责任链模式
  2. 当必须按顺序执行多个处理者时,可以使用该模式
  3. 如果所需处理者及其顺序必须在运行时进行改变,可以使用责任链模式

我们来模拟一个例子:工人请假,如果请假天数小于等于 3 天,由组长审核批准;如果请假天数大于 3 天,小于等于 7 天,由经理审核批准;如果请假天数大于 7 天,由总监审核批准。

#include <cstdio>                                                                                                                                       
#include <string>

class Note{
public:
    std::string name;
    int days;

public:
    Note(const std::string &name, int days)
    :name(name), days(days){}
};

class Manager{
protected:
    Manager *successor;

public:
    Manager()
    :successor(nullptr){}

    virtual ~Manager() = default;

public:
    void setSuccessor(Manager *successor){
        this->successor = successor;
    }

    virtual void handleRequest(const Note &note) = 0;
};

class Leader : public Manager{
public:
     void handleRequest(const Note &note) override{
         if(note.days <= 3)
             printf("Approve %s's leave. ---Leader\n", note.name.c_str());
         else if(this->successor != nullptr)
             this->successor->handleRequest(note);
     }
};

class Director : public Manager{
public:
     void handleRequest(const Note &note) override{
         if(note.days > 3 && note.days <= 7)
             printf("Approve %s's leave. ---Director\n", note.name.c_str());
         else if(this->successor != nullptr)
             this->successor->handleRequest(note);
     }
};

class Majordomo : public Manager{
public:
     void handleRequest(const Note &note) override{
         if(note.days > 7)
             printf("Approve %s's leave. ---Majordomo\n", note.name.c_str());
         else if(this->successor != nullptr)
             this->successor->handleRequest(note);
     }
};

int main(void){
    Leader leader;
    Director director;
    Majordomo majordomo;

    leader.setSuccessor(&director);
    director.setSuccessor(&majordomo);
    
    leader.handleRequest(Note{"Alice", 2});
    leader.handleRequest(Note{"Alice", 5});
    leader.handleRequest(Note{"Alice", 10});
    return 0;
}

二. 享元模式

享元模式:运用共享技术有效地支持大量细粒度的对象

享元对象能做到共享的关键是区分内部状态和外部状态

  1. 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态是可以共享的状态
  2. 外部状态是随环境改变而改变、不可以共享的状态

应用场景:

  1. 程序需要生成数量巨大的相似对象
  2. 对象中包含可抽取且能在多个对象间共享的重复状态

我们来模拟一个例子:五子棋

include <cstdio>                                                                                                                                       
#include <string>
#include <utility>
#include <memory>
#include <unordered_map>

class Chess{
private:
    std::string color;

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

    virtual ~Chess() = default;    

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

class Black : public Chess{
public:
    Black()
    :Chess("black"){}
};

class White : public Chess{
public:
    White()
    :Chess("White"){}
};

class ChessPos{
private:
    std::pair<int, int> pos;
    std::shared_ptr<Chess> chess;

public:
    void setPos(int x, int y){
        this->pos.first = x;
        this->pos.second = y;
    }

    void setChess(const std::shared_ptr<Chess> &chess){
        this->chess = chess;
    }

    void show(void) const{
        printf("%s: (%d, %d)\n", this->chess->getColor().c_str(), this->pos.first, this->pos.second);
    }
};

class CreateChess{
private:
    std::unordered_map<std::string, std::shared_ptr<Chess>> chess_type;

public:
    CreateChess(){
        this->chess_type["black"] = std::make_shared<Black>();
        this->chess_type["white"] = std::make_shared<White>();
    }

public:
    std::unique_ptr<ChessPos> createChess(const std::string &color, int x, int y){
        if(this->chess_type.find(color) != this->chess_type.end()){
            auto res = std::make_unique<ChessPos>();
            res->setChess(this->chess_type[color]);
            res->setPos(x, y);
            return res;
        }
        else{
            printf("The color piece does not exist.\n");
            return nullptr;
        }
    }
};

int main(void){
    CreateChess create_chess;
    std::shared_ptr<ChessPos> chess_1 = create_chess.createChess("black", 3, 4);
    std::shared_ptr<ChessPos> chess_2 = create_chess.createChess("white", 5, 5);

    chess_1->show();
    chess_2->show();
    return 0;
}

三. 命令模式

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作

应用场景:

  1. 如果你需要操作参数化对象,可使用命令模式
  2. 如果你想要将操作放入队列中、操作的执行或者远程执行操作,可使用命令模式
  3. 如果你想要实现操作回滚功能,可使用命令模式

我们来模拟一个例子:使用开关控制电灯

include <cstdio>                                                                                                                                       
#include <string>
#include <unordered_map>
#include <memory>

class Light{
public:
    void turnOn(void) const{
        printf("The light is on.\n");
    }
    
    void turnOff(void) const{
        printf("The light is off.\n");
    }
};

class Command{
public:
    virtual ~Command() = default;

public:
    virtual void run(void) = 0;
};

class TurnOn : public Command{
private:
    Light &light;

public:
    TurnOn(Light &light)
    :light(light){}

public:
    void run(void) override{
        this->light.turnOn();
    }
};

class TurnOff : public Command{
private:
    Light &light;

public:
    TurnOff(Light &light)
    :light(light){}

public:
    void run(void) override{
        this->light.turnOff();
    }
};

class OnOff{
private:
    std::unordered_map<std::string, std::unique_ptr<Command>> on_off;

public:
    explicit OnOff(Light &light){
        this->on_off["on"] = std::make_unique<TurnOn>(light);
        this->on_off["off"] = std::make_unique<TurnOff>(light);
    }

public:
    void click(const std::string &button){
        this->on_off[button]->run();
    }
};

int main(void){
    Light light;
    OnOff on_off(light);
    on_off.click("on");
    on_off.click("off");
    return 0;
}

三. 中介者模式

中介者模式:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

应用场景:

  1. 当一些对象和其它对象紧密耦合以致难以对其进行修改时,可使用中介者模式
  2. 当组件因过于依赖其它组件而无法在不同应用中复用时,可使用中介者模式

我们来模拟一个例子:通过中介找房子

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

class HouseInfor{
public:
    int house_size;
    double house_price;
    std::string house_pos;

public:
    explicit HouseInfor(const std::string &house_pos, int house_size, double house_price)
    :house_pos(house_pos), house_size(house_size), house_price(house_price){}
};

class HouseOwner{
private:
    std::string name;
    std::string phone;

public:
    explicit HouseOwner(const std::string &name, const std::string &phone)
    :name(name), phone(phone){}

    virtual ~HouseOwner() = default;
public:
    std::string getName(void) const{
        return this->name;
    }
    
    std::string getPhone(void) const{
        return this->phone;
    }

    virtual std::unique_ptr<HouseInfor> getHouseInfor(void) = 0; 
};

class Alice : public HouseOwner{
public:
    Alice()
    :HouseOwner("Alice", "15570998888"){}

public:
    std::unique_ptr<HouseInfor> getHouseInfor(void) override{
        return std::make_unique<HouseInfor>("河南省洛阳市金水区万里花园", 30, 700);
    }
};

class Jack : public HouseOwner{
public:
    Jack()
    :HouseOwner("Jack", "19970998888"){}

public:
    std::unique_ptr<HouseInfor> getHouseInfor(void) override{
        return std::make_unique<HouseInfor>("山西省西安市新城区阳光花园", 60, 1500);
    }
};

class Agency{
private:
    std::list<HouseOwner *> house_owners; 

public:
    void addOwner(std::initializer_list<HouseOwner *> house_owners){
        for(const auto &elem : house_owners)
            this->house_owners.emplace_back(elem);
    }

    void removeOwner(std::initializer_list<HouseOwner *> house_owners){
        for(const auto &elem : house_owners)
            this->house_owners.remove(elem);
    }

    void showAll(void){
        for(const auto &elem : this->house_owners){
            auto house_info = elem->getHouseInfor();
            printf("HousePos: %s   HouseSize: %d   HousePrice: %.2lf/month   Phone: %s\n", house_info->house_pos.c_str(), house_info->house_size, house_info->house_price, elem->getPhone().c_str());
         }
    }

    template<typename T>
    void filter(const T &cond){
        for(const auto &elem : this->house_owners){
            auto house_info = elem->getHouseInfor();
            if(cond(*house_info))
                printf("HousePos: %s   HouseSize: %d   HousePrice: %.2lf/month   Phone: %s\n", house_info->house_pos.c_str(), house_info->house_size, house_info->house_price, elem->getPhone().c_str());

        }    
    }
};

int main(void){
    Alice alice;
    Jack jack;
    Agency agency;
    agency.addOwner({&alice, &jack});
    agency.filter([](const HouseInfor &house_info){ return house_info.house_price > 1000; });
    return 0;
}