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

news2024/9/27 12:17:07

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

KubeSphere 核心实战之一【在kubesphere平台上部署mysql】(实操篇 1/4)

文章目录 1、登录kubesphere平台2、kubesphere部署应用分析2.1、工作负载2.2、服务2.3、应用路由2.4、任务2.5、存储与配置2.6、部署应用三要素 3、部署mysql3.1、mysql容器启动实例3.2、mysql部署分析3.3、创建mysql的配置3.4、创建mysql的数据卷pvc3.5、创建mysql工作负载3.6…

力扣第236题——二叉树的最近公共祖先 (C语言题解)

题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以…

C#MQTT编程07--MQTT服务器和客户端(wpf版)

1、前言 上篇完成了winform版的mqtt服务器和客户端&#xff0c;实现了订阅和发布&#xff0c;效果666&#xff0c;长这样 这节要做的wpf版&#xff0c;长这样&#xff0c;效果也是帅BBBB帅&#xff0c;wpf技术是cs程序软件的福音。 wpf的基础知识和案例项目可以看我的另一个专…

定义域【高数笔记】

【定义域】 1&#xff0c;{知识点} 对于一个函数&#xff0c;f(x)&#xff0c;"f"是起到两个作用&#xff0c;第一&#xff0c;是对自变量的范围的约束&#xff0c;第二&#xff0c;是对运算的约束&#xff0c;同一个"f" 就有同一个约束效果 2&#xff0c;…

TPU编程竞赛系列|第八届集创赛“算能杯“报名开启!

近日&#xff0c;第八届全国大学生集成电路创新创业大赛正式开幕&#xff0c;"算能杯"以 基于TPU处理器的边缘计算系统设计 为赛题&#xff0c;围绕算能提供的多款TPU硬件&#xff0c;展开软硬件协同设计&#xff0c;创新开发算法及探索新兴应用。我们诚邀全国高校的…

表的增删改查 进阶(二)

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;MySql&#x1f4d5;格言&#xff1a;那些在暗处执拗生长的花&#xff0c;终有一日会馥郁传香欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 3.新增 4.查询 聚合查询 聚合函数 GROUP BY子句 HA…

php反序列化之pop链构造(基于重庆橙子科技靶场)

常见魔术方法的触发 __construct() //创建类对象时调用 __destruct() //对象被销毁时触发 __call() //在对象中调用不可访问的方法时触发 __callStatic() //在静态方式中调用不可访问的方法时触发 __get() //调用类中不存在变量时触发&#xff08;找有连续箭头的…

Git学习笔记(第3章):Git常用命令

目录 3.1 设置用户签名 3.2 初始化本地库 3.3 查看本地库状态 3.4 添加暂存区 3.5 提交本地库 3.6 历史版本 3.7 修改文件 3.8 版本穿梭 小结 命令 作用 git config --global user.name 用户名 设置用户签名 git config --global user.email 邮箱 设置用户签名 …

机器学习顶会ICLR 2024录用论文合集,包含时间序列、图大模型、agent等热门主题

朋友们&#xff0c;ICLR 2024这周放榜了&#xff01;据统计&#xff0c;本届会议共收到了7262篇论文&#xff0c;整体接收率约为31%&#xff0c;与去年&#xff08;31.8%&#xff09;基本持平。其中Spotlight论文比例为5%&#xff0c;Oral论文比例为1.2%。 不知道各位看完有什…

排序链表(LeetCode 148)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路参考文献 1.问题描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff…

经典计算机网络面试题

1.说说HTTP常用的状态码及其含义&#xff1f; 状态码 类别 1xx 信息性状态码 2xx 成功状态码 3xx 重定向状态码 4xx 客户端错误状态码 5xx 服务端错误状态码 日常开发中的状态码&#xff1a; 状态码 含义 101 切换请求协议 200 请求成功 301 永久性重定向&…

网络:FTP

1. FTP 文件传输协议&#xff0c;FTP是用来传输文件的协议。使用FTP实现远程文件传输的同时&#xff0c;还可以保证数据传输的可靠性和高效性。 2. 特点 明文传输。 作用&#xff1a;可以从服务器上下载文件&#xff0c;或将本地文件上传到服务器。 3. FTP原理 FTP有控制层面…

原神官网切换效果

这两天来研究一下原神游戏官网的效果&#xff0c;地址&#xff1a;《原神》官方网站-全新4.3版本「蔷薇与铳枪」上线&#xff01; (mihoyo.com) 继续用我之前的模板项目&#xff1a; 等我把这一页写满&#xff0c;会上传原码。 效果很多&#xff0c;我们先看第一个&#xff…

数学建模美赛资料(赛题+获奖论文更新)

数学建模美赛历年真题可以帮助我们了解比赛的出题思路&#xff0c;对建模比赛有一个大致的了解。 在备赛过程中&#xff0c;通过往年真题&#xff0c;我们可以了解考试的范围和重点&#xff0c;做到心中有数&#xff0c;可以有的放矢。通过真题&#xff0c;我们可以感受到各个…

逻辑运算符

逻辑运算符 什么是逻辑运算符&#xff1f; 在数学中&#xff0c;一个数据x大于5&#xff0c;小于15&#xff0c;我们可以这样来进行表示&#xff1a;5<x<15.在Java中&#xff0c;需要把上面的式子先进行拆解&#xff0c;再进行合并表达。 拆解为&#xff1a;x>5和 x…

Python中HTTP代理的配置和使用

在Python中&#xff0c;HTTP代理是一种常用的技术&#xff0c;用于控制和修改HTTP请求和响应。通过使用HTTP代理&#xff0c;我们可以更好地控制网络请求的行为&#xff0c;提高安全性、隐私性和效率。下面我们将详细介绍如何在Python中配置和使用HTTP代理。 一、配置HTTP代理…

泛型编程——模板详解

文章目录 1. 前言2. 泛型编程3. 函数模板3.1 函数模板的概念3.2 函数模板的格式3.3 函数模板的原理3.4 函数模板的实例化3.5 模板参数的匹配原则 4. 类模板4.1 类模板的定义格式4.2 类模板的实例化 5. 模板参数6. 模板的特化6.1 概念6.2 函数模板特化6.3 类模板特化6.3.1 全特化…

【STM32】STM32学习笔记-I2C通信外设(34)

00. 目录 文章目录 00. 目录01. I2C简介02. I2C外设简介03. I2C框图04. I2C基本结构05. 主机发送06. 主机接收07. 软件/硬件波形对比08. 预留09. 附录 01. I2C简介 I2C(Inter&#xff0d;Integrated Circuit)总线是一种由NXP&#xff08;原PHILIPS&#xff09;公司开发的两线式…

链表练习 Leetcode234.回文链表

题目传送门&#xff1a;Leetcode234 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&…

element中表格组件的row-class-name和class-name属性的使用以及无效处理

1.这两个属性的使用&#xff0c;row-class-name用在el-table标签上&#xff0c;class-name用在el-table-column标签上。两个属性即可绑定类名也可绑定函数 <!-- 这里是绑定函数&#xff0c;也可以绑定类名 --> <el-table :data"tableData" selection-chang…