C++ 设计模式之备忘录模式

【声明】本题目来源于卡码网(题目页面 (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.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/334032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用万能头 #include<bits/stdc++.h>

准备蓝桥杯的时候看到了很多头文件包含了这个头文件&#xff0c;后来查了一下 它是C中支持的一个几乎万能的头文件&#xff0c;几乎包含所有的可用到的C库函数。以后写代码就可以直接引用这一个头文件了&#xff0c;不需要在写一大堆vector、string、map、stack…… 我们该如何…

zookeeper弱密码漏洞修复

1.连接zookeeper 进入zookeeper安装目录 bin目录下 ./zkCli.sh -server IP:21812.查看节点 ls /3.查看节点权限 getAcl /zookeeper4.设置IP权限 setAcl / ip:127.0.0.1:cdrwa,ip:10.86.30.11:cdrwazookeeper的权限不具备继承性,父子节点的权限相互独立,因此需要为每个子…

论文阅读笔记AI篇 —— Transformer模型理论+实战 (三)

论文阅读笔记AI篇 —— Transformer模型理论实战 &#xff08;三&#xff09; 第三遍阅读&#xff08;精读&#xff09;3.1 Attention和Self-Attention的区别&#xff1f;3.2 Transformer是如何进行堆叠的&#xff1f;3.3 如何理解Positional Encoding&#xff1f;3.x 文章涉及…

浅析Redis①:命令处理核心源码分析(上)

写在前面 Redis作为我们日常工作中最常使用的缓存数据库&#xff0c;其重要性不言而喻&#xff0c;作为普调开发者&#xff0c;我们在日常开发中使用Redis&#xff0c;主要聚焦于Redis的基层数据结构的命令使用&#xff0c;很少会有人对Redis的内部实现机制进行了解&#xff0c…

龙哥的问题(积性函数,莫比乌斯反演)

题目路径&#xff1a; 221. 龙哥的问题 - AcWing题库 思路&#xff1a;

golang 中使用 statik 将静态资源编译进二进制文件中

现在的很多程序都会提供一个 Dashboard 类似的页面用于查看程序状态并进行一些管理的功能&#xff0c;通常都不会很复杂&#xff0c;但是其中用到的图片和网页的一些静态资源&#xff0c;如果需要用户额外存放在一个目录&#xff0c;也不是很方便&#xff0c;如果能打包进程序发…

《游戏-01_2D-开发》

首先利用安装好的Unity Hub创建一个unity 2D&#xff08;URP渲染管线&#xff09;项目 选择个人喜欢的操作格局&#xff08;这里采用2 by 3&#xff09; 在Project项目管理中将双栏改为单栏模式&#xff08;个人喜好&#xff09; 找到首选项&#xff08;Preferences&#xff09…

带你学C语言-指针(4)

目录 ​编辑 ⚾0.前言 &#x1f3c0;1.回调函数 ⚽2.qsort &#x1f3c9;2.1 qsort函数的模拟实现 &#x1f3be;3.sizeof与strlen对比 &#x1f3be;4.结束语 ⚾0.前言 言C之言&#xff0c;聊C之识&#xff0c;以C会友&#xff0c;共向远方。各位CSDN的各位你们好啊&…

docker 使用 vcs/2018 Verdi等 eda 软件

好不容易在ubuntu 安装好了eda软件&#xff0c;转眼就发现了自己的无知。 有博主几年前就搞定了docker上的EDA工具。而且更全&#xff0c;更简单。只恨自己太无知啊。 Synopsys EDA Tools docker image - EDA资源使用讨论 - EETOP 创芯网论坛 (原名&#xff1a;电子顶级开发网…

OB OCP工具

文章目录 OCP产品架构OCP核心功能集群管理-集群拓扑图告警管理 OCP OCP&#xff08;OceanBase Cloud Platform&#xff09;是企业级数据库管理平台OceanBase 云平台&#xff08;OceanBase Cloud Platform&#xff0c;OCP&#xff09;是以 OceanBase 为核心的企业级数据库管理平…

2024年【焊工(初级)】考试总结及焊工(初级)模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 焊工&#xff08;初级&#xff09;考试总结是安全生产模拟考试一点通总题库中生成的一套焊工&#xff08;初级&#xff09;模拟考试&#xff0c;安全生产模拟考试一点通上焊工&#xff08;初级&#xff09;作业手机同…

canvas绘制图形

目录 1、canvas绘制矩形 2、canvas绘制线 3、canvas绘制圆 4、canvas绘制多圈动画圆 HTML5<canvas>元素用于图形的绘制&#xff0c;Canvas API主要聚焦于2D图形。 1、canvas绘制矩形 canvas是一个二维网格&#xff0c;左上角坐标为(0,0)&#xff0c;横轴为x轴&…

Redis实战之-分布式锁

一、基本原理和实现方式对比 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#xff0c;让程序串行…

【jQuery入门】基础使用-入口函数、顶级对象$

文章目录 前言一、基础使用1.1 jQuery的下载1.2 简单的使用 二、顶级对象$总结 前言 jQuery是一款广泛应用于前端开发的JavaScript库&#xff0c;它简化了许多常见任务的操作&#xff0c;使得代码编写更加便捷。本文将介绍jQuery的基础使用&#xff0c;包括入口函数和顶级对象…

SQL注入实战操作

一&#xff1a;SQl注入分类 按照注入的网页功能类型分类&#xff1a; 1、登入注入&#xff1a;表单&#xff0c;如登入表单&#xff0c;注册表单 2、cms注入&#xff1a;CMS逻辑:index.php首页展示内容&#xff0c;具有文章列表(链接具有文章id)、articles.php文 章详细页&a…

Python自测+回答汇合传送门以及语法思维图

自测题目 Python语法自测1&#xff1a;注释输入输出变量格式化输出标识符运算符 Python语法自测2&#xff1a;数据类型类型转换条件循环 Python语法自测3&#xff1a;列表元组字符串集合公共语法 Python语法自测4&#xff1a;函数类和对象模块导入 Python语法自测5&#xff1a…

ASEPRITE使用笔记

aseprite学习笔记 快捷键 新建图层后,按快捷键c可以调出画布属性框放大缩小画布快捷键,鼠标滚轮移动画布快捷键,空格ctr+d,取消选取基本概念 软件五个基本区域:菜单栏、工具属性栏、工具栏、图层栏、颜色栏颜色栏分为色板和调色区域注意事项 创造时,需要把输入法调整成应…

Linux粘滞位的理解,什么是粘滞位?

文章目录 前言如何理解&#xff1f;粘滞位的操作最后总结一下 前言 粘滞位&#xff08;Stickybit&#xff09;&#xff0c;或粘着位&#xff0c;是Unix文件系统权限的一个旗标。最常见的用法在目录上设置粘滞位&#xff0c;如此以来&#xff0c;只有目录内文件的所有者或者root…

HTML 表单

文章目录 表单什么是表单GET和POST两种提交方式有什么不同?表单元素表单项外文本单行文本输入框单行文本密码框单选框复选框下拉列表框上传文件隐藏域填写邮箱填写电话填写数字填写日期进度条多行文本输入框提交按钮取消按钮 用户注册案例 表单 什么是表单 form:表单元素 此…

MySQL 查询数据

今天介绍一下 MySQL 数据库使用 SELECT 语句来查询数据。 语法 首先&#xff0c;介绍一下语法。以下为在 MySQL 数据库中查询数据通用的 SELECT 语法&#xff1a; SELECT column1, column2, ... FROM table_name [WHERE condition] [ORDER BY column_name [ASC | DESC]] [LI…