备忘录模式--行为模式

1、描述

备忘录是一种行为设计模式,允许生成对象状态的快照并在以后将其还原。

备忘录不会影响它所处理的对象的内部结构,也不会影响快照中保存的数据。

2、结构图

  • 原发器(Originator)可以生成自身状态的快照,也可以在需要时通过快照恢复自身状态。
  • 备忘录(Memento)是原发器状态快照的值对象。通常做法是将备忘录设为不可变的,并通过构造函数一次性传递数据。
  • 负责人(Caretaker)对备忘录进行管理、保存和提供备忘录。

3、C++代码

#include <string>
#include <iostream>
#include <vector>
#include <time.h>

//备忘录接口提供了一种获取元数据的方法,例如创建日期或名称。但是,它不会暴露原发器的状态
class Memento {
 public:
  virtual std::string GetName() const = 0;
  virtual std::string date() const = 0;
  virtual std::string state() const = 0;
};

//具体的备忘录类包含了存储原发器状态的基础设施
class ConcreteMemento : public Memento {
 private:
  std::string state_;
  std::string date_;

 public:
  ConcreteMemento(std::string state) : state_(state) {
    this->state_ = state;
    time_t now = time(0);
    this->date_ = ctime(&now);
  }

  //原发器使用这个方法恢复它的状态
  std::string state() const override {
    return this->state_;
  }

  //其他的方法由负责人使用来展示元数据
  std::string GetName() const override {
    return this->date_ + " / (" + this->state_.substr(0, 9) + "...)";
  }
  std::string date() const override {
    return this->date_;
  }
};

//原发器包含一些可能会随着时间改变的重要的状态。它也定义了一个方法用来将状态保存到备忘录和
//另一个方法用来从备忘录中恢复状态
class Originator {

 private:
  std::string state_;

  std::string GenerateRandomString(int length = 10) {
    const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
    int stringLength = sizeof(alphanum) - 1;

    std::string random_string;
    for (int i = 0; i < length; i++) {
      random_string += alphanum[std::rand() % stringLength];
    }
    return random_string;
  }

 public:
  Originator(std::string state) : state_(state) {
    std::cout << "Originator: My initial state is: " << this->state_ << "\n";
  }

  //原发器的业务逻辑可能会改变其内部状态。因此,客户需要在调用该方法前备份状态。
  void DoSomething() {
    std::cout << "Originator: I'm doing something important.\n";
    this->state_ = this->GenerateRandomString(30);
    std::cout << "Originator: and my state has changed to: " << this->state_ << "\n";
  }

  //将当前状态备份到备忘录中
  Memento *Save() {
    return new ConcreteMemento(this->state_);
  }

  //从备忘录中恢复状态
  void Restore(Memento *memento) {
    this->state_ = memento->state();
    std::cout << "Originator: My state has changed to: " << this->state_ << "\n";
  }
};

//负责人并不依赖具体的备忘录类。因此,它并不需要获取保存在备忘录中的原发器状态。
//它只通过备忘录基类接口操作所有的备忘录
class Caretaker {

 private:
  std::vector<Memento *> mementos_;

  Originator *originator_;

 public:
  Caretaker(Originator *originator) : originator_(originator) {
    this->originator_ = originator;
  }

  void Backup() {
    std::cout << "\nCaretaker: Saving Originator's state...\n";
    this->mementos_.push_back(this->originator_->Save());
  }
  void Undo() {
    if (!this->mementos_.size()) {
      return;
    }
    Memento *memento = this->mementos_.back();
    this->mementos_.pop_back();
    std::cout << "Caretaker: Restoring state to: " << memento->GetName() << "\n";
    try {
      this->originator_->Restore(memento);
    } catch (...) {
      this->Undo();
    }
  }
  void ShowHistory() const {
    std::cout << "Caretaker: Here's the list of mementos:\n";
    for (Memento *memento : this->mementos_) {
      std::cout << memento->GetName() << "\n";
    }
  }
};

//客户端代码
void ClientCode() {
  Originator *originator = new Originator("Super-duper-super-puper-super.");
  Caretaker *caretaker = new Caretaker(originator);
  caretaker->Backup();
  originator->DoSomething();
  caretaker->Backup();
  originator->DoSomething();
  caretaker->Backup();
  originator->DoSomething();
  std::cout << "\n";
  caretaker->ShowHistory();
  std::cout << "\nClient: Now, let's rollback!\n\n";
  caretaker->Undo();
  std::cout << "\nClient: Once more!\n\n";
  caretaker->Undo();

  delete originator;
  delete caretaker;
}

int main() {
  std::srand(static_cast<unsigned int>(time(NULL)));
  ClientCode();
  return 0;
}

参考

https://refactoringguru.cn/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值