【声明】本题目来源于卡码网(题目页面 (kamacoder.com))
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】
【设计模式大纲】
【简介】
-- 什么是备忘录模式 (第17种模式)
备忘录模式(Memento Pattern)是⼀种⾏为型设计模式,它允许在不暴露对象实现的情况下捕获对象的内部状态并在对象之外保存这个状态,以便稍后可以将其还原到先前的状态。
【基本结构】
备忘录模式包括以下⼏个重要⻆⾊:
- 发起⼈Originator : 需要还原状态的那个对象,负责创建⼀个【备忘录】,并使⽤备忘录记录当前时刻的内部状态。
- 备忘录Memento : 存储发起⼈对象的内部状态,它可以包含发起⼈的部分或全部状态信息,但是对外部是不可⻅的,只有发起⼈能够访问备忘录对象的状态。
备忘录有两个接⼝,发起⼈能够通过宽接⼝访问数据,管理者只能看到窄接⼝,并将备忘录传递给其他对象。
- 管理者Caretaker : 负责存储备忘录对象,但并不了解其内部结构,管理者可以存储多个备忘录对象。
- 客户端:在需要恢复状态时,客户端可以从管理者那⾥获取备忘录对象,并将其传递给发起⼈进⾏状态的恢复。
【基本实现】
下面以Java代码作以简要说明:
1. 创建发起⼈类:可以创建备忘录对象
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
// 创建备忘录对象
public Memento createMemento() {
return new Memento(state);
}
// 通过备忘录对象恢复状态
public void restoreFromMemento(Memento memento) {
state = memento.getState();
}
}
2. 创建备忘录类:保存发起⼈对象的状态
class Memento {
private String state;
// 保存发起⼈的状态
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
3. 创建管理者:维护⼀组备忘录对象
class Caretaker {
private List<Memento> mementos = new ArrayList<>();
public void addMemento(Memento memento) {
mementos.add(memento);
}
public Memento getMemento(int index) {
return mementos.get(index);
}
}
4. 客户端使用备忘录模式
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file MementoMode.hpp
* @brief 备忘录模式
* @autor 写代码的小恐龙er
* @date 2024/01/19
*/
public class Main {
public static void main(String[] args) {
// 创建发起⼈对象
Originator originator = new Originator();
originator.setState("State 1");
// 创建管理者对象
Caretaker caretaker = new Caretaker();
// 保存当前状态
caretaker.addMemento(originator.createMemento());
// 修改状态
originator.setState("State 2");
// 再次保存当前状态
caretaker.addMemento(originator.createMemento());
// 恢复到先前状态
originator.restoreFromMemento(caretaker.getMemento(0));
System.out.println("Current State: " + originator.getState());
}
}
【使用场景】
备忘录模式在保证了对象内部状态的封装和私有性前提下可以轻松地添加新的备忘录和发起⼈,实现“备份”,不过备份对象往往会消耗较多的内存,资源消耗增加。
备忘录模式常常⽤来实现撤销和重做功能,⽐如在Java Swing GUI编程中,javax.swing.undo 包中的撤销(undo)和重做(redo)机制使⽤了备忘录模式。UndoManager 和UndoableEdit 接⼝是与备忘录模式相关的主要类和接⼝。
【C++编码部分】
1. 题目描述
小明正在设计一个简单的计数器应用,支持增加(Increment)和减少(Decrement)操作,以及撤销(Undo)和重做(Redo)操作,请你使用备忘录模式帮他实现。
2. 输入描述
输入包含若干行,每行包含一个字符串,表示计数器应用的操作,操作包括 "Increment"、 "Decrement"、"Undo" 和 "Redo"。
3. 输出描述
对于每个 "Increment" 和 "Decrement" 操作,输出当前计数器的值,计数器数值从0开始 对于每个 "Undo" 操作,输出撤销后的计数器值。 对于每个 "Redo" 操作,输出重做后的计数器值。
4. C++编码实例
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file MementoMode.hpp
* @brief 备忘录模式
* @autor 写代码的小恐龙er
* @date 2024/01/19
*/
#include <iostream>
#include <string>
#include <vector>
#include <stack>
using namespace std;
// 前置声明
// 备忘录类 -- 保存发起⼈对象的状态
class Memento;
// 发起人类 -- 可以创建备忘录对象
class Counter;
// 管理者 -- 一组备忘录对象
class MementoManager;
// 类的定义
// 备忘录类
class Memento
{
// 成员数据
private:
int _value;
// 备忘录操作的成员函数
public:
Memento(int value){
SetValue(value);
}
void SetValue(int value){
this->_value = value;
}
int GetValue(){
return this->_value;
}
};
// 发起人 类
class Counter
{
// 成员数据
private:
int _value;// 发起人的计数值
std::stack<Memento *> _undoStack; // 发起人撤销操作的栈
std::stack<Memento *> _redoStack; // 发起人重新操作的栈
// 成员函数
public:
Counter(){}
// 获取值
int GetValue(){
return this->_value;
}
// 增加计数值
void IncreaseValue(Memento *memento){
//清空重做的栈
while(!_redoStack.empty()){
_redoStack.pop();
}
_undoStack.push(memento);
_value++;
}
// 减少计数值
void DecreaseValue(Memento *memento){
//清空重做的栈
while(!_redoStack.empty()){
_redoStack.pop();
}
_undoStack.push(memento);
_value--;
}
// 撤销操作
void Undo(Memento *memento){
if(!_undoStack.empty()){
_redoStack.push(memento);
_value = _undoStack.top()->GetValue();
}
}
// 重新操作
void Redo(Memento *memento){
if(!_redoStack.empty()){
_undoStack.push(memento);
_value = _redoStack.top()->GetValue();
}
}
};
// 管理者
class MementoManager
{
// 成员数据
private:
std::vector<Memento *> _mementoVec;
// 成员函数
public:
// 增加备忘录
void AddMemento(Memento *mento){
_mementoVec.push_back(mento);
}
// 寻找备忘录 按照顺序 或者 备忘录中的计数值
Memento * GetMemento(int index){
if(index >= _mementoVec.size()) return nullptr;
else return _mementoVec[index];
}
};
// 客户端
int main()
{
// 操作类型
string type = "";
// 新建 发起人 类
Counter *counter = new Counter();
// 新建备忘录管理者
MementoManager *manager = new MementoManager();
// 新建备忘录
Memento *memento = nullptr;
// 等待输入指令
while(std::cin >> type){
if(type == "Increment"){
memento = new Memento(counter->GetValue());
counter->IncreaseValue(memento);
}
else if(type == "Decrement"){
memento = new Memento(counter->GetValue());
counter->DecreaseValue(memento);
}
else if(type == "Undo"){
memento = new Memento(counter->GetValue());
counter->Undo(memento);
}
else if(type == "Redo"){
memento = new Memento(counter->GetValue());
counter->Redo(memento);
}
// 将备忘录添加至管理者中 【此时备忘录管理者可以去做其他的事情】
manager->AddMemento(memento);
// 输出计数器的值
std::cout<< counter->GetValue() << endl;
}
// 析构
if(memento != nullptr){
delete memento;
memento = nullptr;
}
delete counter;
counter = nullptr;
delete manager;
manager = nullptr;
return 0;
}
......
To be continued.