Android设计模式之——备忘录模式

一、介绍

备忘录模式是一种行为模式,该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态,这有点像我们平时说的”后悔药“。备忘录模式实现的方式需要保证被保存的对象状态不能被对象从外部访问,目的是为了保护好被保存的这些对象状态的完整性以及内部实现不向外暴露。

二、定义

在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样,以后就可将该对象恢复到原先保存的状态。

三、使用场景

  • 需要保存一个对象在某一个时刻的状态或部分状态。

  • 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其内部状态。

四、备忘录模式的UML类图

UML类图:

这里写图片描述

角色介绍:

  • Originator:负责创建一个备忘录,可以记录、恢复自身的内部状态。同时Originator还可以根据需要决定Memento存储自身的哪些内部状态。

  • Memento:备忘录角色,用于存储Originator的内部状态,并且可以防止Originator以外的对象访问Memento。

  • Caretaker:负责存储备忘录,不能对备忘录的内容进行操作和访问,只能将备忘录传递给其他对象。

五、简单示例

对备忘录模式来说,比较贴切的场景应该是游戏中的存档功能,该功能就是将游戏进度存储到本地文件系统或数据库中,下次再次进入时从本地加载进度,使得玩家能够继续上一次的游戏之旅,这里我们就以”使命召唤“这款游戏为例来简单演示一下备忘录模式的实现。

首先我们建立游戏类、备忘录类、Caretaker类,玩游戏到某个节点对游戏进行存档,然后退出游戏,再重新进入时从存档中读取进行,并且进入存档时的进度。

游戏类:

/*** * 简单模拟“使命召唤”游戏 * */public class CallOfDuty {private int mCheckpoint = 1;private int mLiftValue = 100;private String mWeapon = "沙漠之鹰";//玩游戏public void play(){System.out.println("打游戏:"+String.format("第%d关", mCheckpoint) + "奋战杀敌中");mLiftValue -= 10;System.out.println("进度升级了");mCheckpoint++;System.out.println("到达" + String.format("第%d关", mCheckpoint));}//退出游戏public void quit(){System.out.println("--------------");System.out.println("退出前的游戏属性:" + this.toString());System.out.println("退出游戏");System.out.println("--------------");}/***创建备忘录 */public Memento createMemento(){Memento memento = new Memento();memento.mCheckpoint = mCheckpoint;memento.mLiftValue = mLiftValue;memento.mWeapon = mWeapon;return memento;}//恢复游戏public void restore(Memento memento){this.mCheckpoint = memento.mCheckpoint;this.mLiftValue = memento.mLiftValue;this.mWeapon = memento.mWeapon;System.out.println("恢复后的游戏属性:" + this.toString());}//省略getter和setter方法@Overridepublic String toString() {return "CallOfDuty [mCheckpoint=" + mCheckpoint + ",mLiftValue="+ mLiftValue + ",mWeapon=" + mWeapon + "]";}
}

在CallOfDuty游戏类中,我们存储了几个关键字段,关卡、人物的生命值、武器,当调用play函数玩游戏时,我们对关卡和人物的生命值进行修改。在该类中可以通过createMemoto函数来创建该用户的备忘录对象,也就是将自身的状态保存到一个Memoto对象中。外部可以通过restore函数将CallOfDuty对象的状态从备忘录对象中恢复。

我们在来看下备忘录对象,它只是存储CallOfDuty对象的字段,具体代码如下:

备忘录类:

/*** 备忘录类*/
public class Memento {public int mCheckpoint;//武器public int mLiftValue;//生命public String mWeapon;//关卡@Overridepublic String toString() {return "Memento [mCheckpoint=" + mCheckpoint + ",mLiftValue="+ mLiftValue + ",mWeapon=" + mWeapon + "]";}}

这是一个无状态、无操作的实体类,只负责用来存储Originator角色的一些数据,防止外部直接访问Originator。

而备忘录的操作者则是Caretaker角色,我们看下相关代码:

Caretaker类:

/*** Caretaker,负责管理Memento*/
public class Caretaker {Memento mMemento; //备忘录/*** 存档*/public void archive(Memento memento){this.mMemento = memento;}/*** 获取存档*/public Memento getMemento(){return mMemento;}
}

Caretaker类的职责很简单,就是负责管理Memoto对象,也就是备忘录对象。

客户端类:

public class Client {public static void main(String[] args) {//构建游戏对象CallOfDuty game = new CallOfDuty();//1.打游戏game.play();Caretaker caretaker = new Caretaker();//2.游戏存档caretaker.archive(game.createMemento());//3.退出游戏game.quit();//4.恢复游戏CallOfDuty newGame = new CallOfDuty();newGame.restore(caretaker.getMemento());}
}

结果:

打游戏:第1关奋战杀敌中
进度升级了
到达第2关
--------------
退出前的游戏属性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鹰]
退出游戏
--------------
恢复后的游戏属性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鹰]
打游戏:第2关奋战杀敌中

上述过程大致有如下4步:
(1)开始游戏,闯关升级;
(2)游戏退出之前进行存档;
(3)退出游戏;
(4)重新启动游戏,从存档中恢复游戏进度。

CallOfDuty在这里为Originator角色,也就是需要存储数据的对象,在这里并没有直接存储CallOfDuty的对象,而是通过Memoto对CallOfDuty对象的数据进行存储,然后在存储Memoto对象,最终对Memoto的存取操作则交给Caretaker对象。在这个过程中,各个角色职责清晰、单一,代码也比较简单,即对外屏蔽了对CallOfDuty角色的直接访问,在满足了对象状态存取功能的同时也使得该模块的结构保持清晰、整洁。

六、Android源码中的备忘录模式

1、onSaveInstanceState和onRestoreInstanceState

当Activity不是正常方式退出,且Activity在随后的时间内被系统杀死之前会调用这两个方法让开发人员可以有机会存储Activity相关信息,且在下次返回Activity时恢复这些数据。通过这两个函数。开发人员能够在某些特殊场景下储存与界面相关的信息,提升用户体验。

七、总结

备忘录模式是在不破坏封装的条件下,通过备忘录对象(Memoto)存储另外一个对象内部状态的快照,在将来合适的时候把这个对象还原到存储起来的状态。

优点:

  • 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史状态。

  • 实现了信息的封装,使用户不需要关心状态的保存细节。

缺点:

  • 消耗资源,如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

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

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

相关文章

C++ using的三种使用策略以及具体的用法

Using的使用方法 1,命名空间的使用 为了防止代码冲突,都会使用到命名空间。假设这样一种情况,当一个班上有两个名叫 Zara 的学生时,为了明确区分他们,我们在使用名字之外,不得不使用一些额外的信息&#…

Android设计模式之——迭代器模式

一、介绍 迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是行为型设计模式之一。迭代器模式算是一个比较古老的设计模式,其源于对容器的访问,比如Java中的List、Map、数组等&#xff0c…

Android设计模式之——模板方法模式

一、介绍 在面向对象开发过程中,通常会遇到这样的一个问题,我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序,但是,某些步骤的具体实现是未知的,或者说某些步骤的实现是会随着环境的变化而改变…

Android设计模式之——访问者模式

一、介绍 访问者模式是一种将数据操作与数据结构分离的设计模式,它是《设计模式》中23种设计模式中最复杂的一个,但它的使用频率并不高,正如《设计模式》的作者GOF对访问者模式的描述:大多数情况下,你不需要使用访问者…

Android设计模式之——中介者模式

一、介绍 中介者模式(Mediator Pattern)也称为调解者模式或调停者模式,Mediator本身就有调停者和调解者的意思。 在日常生活中调停者或调解者这个角色我们见得比较多的是“和事老”,也就是说调解两个有争端的人的角色&#xff0…

Java基础——虚拟机结构

一、Java平台结构图二、JVM、JRE和JDK关系JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件 JRE: Java Runtime Environment (java运行环境),包含JVM和类库 JDK&a…

C++:MAC安装Boost库文件并且使用CLion开发

boost的filestem库 C在17版本的标准库中引入了一个filesystem库,用来处理文件路径,以及文件访问。很多编译器对filesystem库的支持还不是很好。为了解决这个问题,可以临时使用boost::filesystem来替代。其实C17标准中的filesystem库就是从bo…

Java基础——Java异常处理机制

一、引言 try…catch…finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解。不过,我亲自体验的“教训”告诉我,这个东西可不是想象中的那么简单、听话。不信?那你看看下面的代码…

clion在使用sqlite3的时候,显示Undefined symbols for architecture x86_64错误的解决办法

显示Undefined symbols for architecture x86_64错误的原因 1、缺少静态库 环境:在模拟器上报错但在真机上能运行成功,而且报的错误来自于第三方库。原因:architecture x86_64 是指模拟器的架构,意思就是 Crypto 变量在模拟器架…

Java基础——类加载机制及原理

一、什么是类的加载? 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Cl…

在Ubuntu环境下使用vcpkg安装sqlite_orm包文件

Ubuntu安装vcpkg 从github下载vcpkg的安装包,在usr/local路径下面执行如下命令 git clone https://github.com/Microsoft/vcpkg.git cd vcpkg //进入源码目录 ./bootstrap-vcpkg.sh //执行./bootstrap-vcpkg.sh进行编译安装,这个过程很慢 编译安装好…

window电脑查看ssh公钥,以及将自己的公钥添加到Github等类似网站

查看本机的ssh公钥 使用命令 cd ~/.ssh使用命令 ls 可以看到 id_rsa id_rsa.pub known_hosts 三个文件,此处需要的是id_rsa.pub文件使用命令 cat id_rsa.pub 查看文件的内容拷贝这段内容 添加自己的公钥 进入账户的设置页面参照如下步骤,进入SSH Key…

java八大排序算法

一、概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大,则应采…

windows安装 Git Large File Storage大文件下载工具ge

下载地址 导航到 git-lfs.github.com 并单击Download开始下载git-lfs的用法指南 验证安装成功 打开Git Bash验证安装成功,使用命令 git lfs install ,如果出现 >Git LFS initlized,就代表安装成功参考链接 安装 Git Large File Storag…

Java基础——volatile关键字解析

简介volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情。由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatile关键…

Java基础——Java IO详解

一、概述 1、Java IO Java IO即Java 输入输出系统。不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO(文件、控…

Java基础——Java NIO详解(二)

一、简介 在我的上一篇文章Java NIO详解(一)中介绍了关于标准输入输出NIO相关知识, 本篇将重点介绍基于网络编程NIO(异步IO)。 二、异步IO 异步 I/O 是一种没有阻塞地读写数据的方法。通常,在代码进行 rea…

Java基础——Java NIO详解(一)

一、基本概念 1、I/0简介 I/O即输入输出,是计算机与外界世界的一个借口。IO操作的实际主题是操作系统。在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过stream对象一次移动一个字节。流IO负责把对象…

解决在sample文件夹里面写代码,在测试的时候因为virtual原因,make编译报错

代码的结构 错误显示 解决办法 添加一句话,具体的cpp依据情况而定set_source_files_properties(${PROJECT_SOURCE_DIR}/src/sample_storage_test.cpp COMPILE_FLAGS "-Wno-unused-parameter")

Android 多进程开发

前言正常情况下,一个apk启动后只会运行在一个进程中,其进程名为AndroidManifest.xml文件中指定的应用包名,所有的基本组件都会在这个进程中运行。但是如果需要将某些组件(如Service、Activity等)运行在单独的进程中&am…