备忘录模式是一种行为型设计模式,顾名思义就是起到备忘的功能。我们常见文本编辑器都有“撤销”的功能,一般对应的键盘映射是Ctrl+z,且可以多次使用返回上上次的历史情况。
那么,实现这种功能的设计模式就是备忘录模式。

基本结构

我们了解了备忘录的实际含义,就来说一下其中存在的几种角色

  1. 发起人Originator:需要还原状态的那个对象,负责创建一个【备忘录】,并使用备忘录记录当前时刻的内部状态。
  2. 备忘录Memento:存储发起人对象的内部状态,他可以包含发起人的部分护着全部状态信息,但是对于外部是不可见的,只有发起人能够访问备忘录对象的状态。
  3. 管理者Caretaker:负责存储备忘录对象,但并不了解其内部结构,管理者可以存储多个备忘录对象(栈)。
  4. 客户端:在需要恢复状态时,客户端可以从管理者那里获取备忘录对象,并将其传给发起人进行状态的恢复。

uml类中,发起人依赖备忘录实现“备忘”,管理者相当于多个备忘录的聚合关系,而客户端宏观上使用备忘录模式。

代码举例

#include<bits/stdc++.h>
using namespace std;


// 备忘录

class Memento {

    public:

    virtual ~Memento() {}

    virtual string GetName() const = 0;

    virtual string date() const = 0;

    virtual string state() const = 0;

};

  

// 具体备忘录

class ConcreteMemento :public Memento {

    private:

    string state_;

    string date_;

    public:

    ConcreteMemento(string state) :state_(state) {

        this->state_ = state; // 记录状态

        time_t now = time(0);

        this->date_ = ctime(&now); // 记录具体的时间

    }

    string state() const override {

        return this->state_;

    }

    string GetName() const override {

        return this->date_ + "/ (" + this->state_.substr(0, 9) + "...)";

    }

    string date() const override {

        return this->date_;

    }

};

// 发起者

class Originator {

    private:

    string state_;

    string GenerateRandomString(int len = 10) {

        const char alphanum[] =

            "0123456789"

            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

            "abcdefghijklmnopqrstuvwxyz";

        int stringlen = sizeof(alphanum) - 1;

  

        string random_string;

        for (int i = 0; i < len; i++) {// 生成随机字符串

            random_string += alphanum[rand() % stringlen];

        }

        return random_string;

    }

    public:

    Originator(string state) :state_(state) {

        cout << "Orignator: My initial state is " << this->state_ << endl;

    }

    void DoSomething() {

        cout << "Orignator: I'm doing something important.\n";

        this->state_ = this->GenerateRandomString(30);

        cout << "Orignator: and my state has changed to " << this->state_ << endl;

    }

  

    Memento* Save() {

        return new ConcreteMemento(this->state_); // 保存当前状态

    }

    void Restore(Memento* memento) { // 恢复之前的状态, 传入备忘录

        this->state_ = memento->state();

        cout << "Originator: My state has changed to: " << this->state_ << endl;

  

    }

};

class Caretaker {

    private:

    vector<Memento*> mementolist;// 备忘录列表,使用数组模拟栈

    Originator* orignator_;

    public:

    Caretaker(Originator* orignator) :orignator_(orignator) {}

    ~Caretaker() { for (auto m : mementolist) delete m; }

  

    void Backup() {

        cout << "\nCaretaker: Saving Originator's state:...\n";

        this->mementolist.push_back(this->orignator_->Save());

    }

    void Undo() {

        if (this->mementolist.empty()) {

            return;

        }

        Memento* mem = this->mementolist.back();

        this->mementolist.pop_back();

        cout << "Caretaker: Restoring state to: " << mem->GetName() << endl;

        try {

            this->orignator_->Restore(mem);

        }

        catch (...) {

            this->Undo(); // 出现异常就回滚

        }

  

    }

    void ShowHistory() {

        cout << "Caretaker: Here's the list of mementos:\n";

        for (auto& it : this->mementolist) {

            cout << it->GetName() << endl;

        }

    }

};

  

// 定义客户端函数

void ClientCode() {

  

    // 创建发起者

    Originator* ori = new Originator("Super-duper-super-puper-super.");
  

    // 创建管理者  

    Caretaker* care = new Caretaker(ori);

    care->Backup();// 备份当前状态
    ori->DoSomething();

  
    care->Backup();
    ori->DoSomething();


    care->Backup();
    ori->DoSomething();

  

    cout << endl;

    care->ShowHistory();

  

    cout << "\nClient: Now, let's roolback!\n";

    care->Undo();

    cout << "\nClien: Once more\n";

    care->Undo();

  

    delete ori, care;

}

int main() {

    //设置随机种子

    srand(static_cast<unsigned int> (time(NULL)));

    // 调用客户端

    ClientCode();

    return 0;

}

输出:

Orignator: My initial state is Super-duper-super-puper-super.

Caretaker: Saving Originator's state:...
Orignator: I'm doing something important.
Orignator: and my state has changed to cWTYThunPtuGSdepH2S3jFPHZlUGIZ

Caretaker: Saving Originator's state:...
Orignator: I'm doing something important.
Orignator: and my state has changed to K6L7mOV7XkLrxbVBoWn7H1BoeO5Qg6

Caretaker: Saving Originator's state:...
Orignator: I'm doing something important.
Orignator: and my state has changed to 9O6w7UfIPpPuZx14x15BWlqR0q6aGv

Caretaker: Here's the list of mementos:
Sun Nov  3 23:46:14 2024
/ (Super-dup...)
Sun Nov  3 23:46:14 2024
/ (cWTYThunP...)
Sun Nov  3 23:46:14 2024
/ (K6L7mOV7X...)

Client: Now, let's roolback!
Caretaker: Restoring state to: Sun Nov  3 23:46:14 2024
/ (K6L7mOV7X...)
Originator: My state has changed to: K6L7mOV7XkLrxbVBoWn7H1BoeO5Qg6

Clien: Once more
Caretaker: Restoring state to: Sun Nov  3 23:46:14 2024
/ (cWTYThunP...)
Originator: My state has changed to: cWTYThunPtuGSdepH2S3jFPHZlUGIZ

上述代码稍显冗长,不过仔细看完,核心在于客户端每次通过caretaker的提前备份(Backup),originator发起人再修改(DoSomething),之后再Undo就可以将vector的末尾弹出替换当前状态,相当于“撤回”功能,这里vector模拟的就是一个栈。

总结一下

备忘录模式将创建状态快照 (Snapshot) 的工作委派给实际状态的拥有者原发器(Originator) 对象。 这样其他对象就不再需要从 “外部” 复制编辑器状态了, 编辑器类拥有其状态的完全访问权, 因此可以自行生成快照。即原发器拥有对备忘录的完全访问权限, 负责人则只能访问元数据。

这种限制策略允许你将备忘录保存在通常被称为_负责人_ (Caretakers) 的对象中。 由于负责人仅通过受限接口与备忘录互动, 故其无法修改存储在备忘录内部的状态。 同时, 原发器拥有对备忘录所有成员的访问权限, 从而能随时恢复其以前的状态。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部