Java设计模式之备忘录模式
作者:tianClassmate 发布时间:2023-08-24 06:17:05
无论是我们在使用word还是记事本,系统都会为我们提供撤销的功能,这几乎是人人都会使用到的功能,而在我们实际开发中,会不会存在一个很复杂的对象,当更改了其中的某一个属性以后,也提供撤销的功能,可以快速恢复到更新前的状态。提供该功能的模式也正是今天的主题——备忘录模式。
一、概念理解
书上备忘录的解释是,在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
其实也就是在一个对象之外再额外的增加一个副本对象,每当我们在对象上更改一些属性以后就构建一个副本,并把副本存放在一个队列中,每当回退该对象的时候就从副本中恢复数据。
很显然需要三个角色:原对象、副本对象、存放副本的队列。
也即书上的三个角色定义:
Originator(发起人角色):负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能;即原对象。
Memento(备忘录角色):用于存储Originator的内部状态,且可以防止Originator以外的对象进行访问;即副本对象。
Caretaker(管理员角色):负责存储、提供管理Memento,无法对Memento的内容进行操作和访问;也即存放副本的队列。
为了让概念落地,我们基于备忘录模式的思想实现视频草稿箱的功能。
在这个业务场景中,发起人其实就是编辑视频的编辑器,在这个编辑器中我们能干啥呢?编辑视频、从草稿箱导入、保存到草稿箱。这不是就是发起人角色的作用吗!我们称为编辑草稿。
备忘录那不就是草稿修改后吗,我们称之为完稿。
完稿做好了,要存放到一个列表中用于我们快速修复,那当然就是管理员角色。
基于三个角色我们实现代码。
二、案例实现
备忘录角色(完稿):
就是个基础对象,用于存储数据,视频包含的属性主要是,标题、封面、视频地址
/**
* 备忘录(完稿)
* @author tcy
* @Date 16-09-2022
*/
public class VideoMemento {
private String title;
private String videoUrl;
private String imgs;
public VideoMemento(String title, String content, String imgs) {
this.title = title;
this.videoUrl = content;
this.imgs = imgs;
}
public String getTitle() {
return title;
}
public String getContent() {
return videoUrl;
}
public String getImgs() {
return imgs;
}
@Override
public String toString() {
return "ArticleMemento{" +
"title='" + title + '\'' +
", content='" + videoUrl + '\'' +
", imgs='" + imgs + '\'' +
'}';
}
}
发起人角色(编辑草稿):
在基本对象之上,增加保存和撤销的操作,可以看到和我们定义的完稿长的一样,只是又增了saveToMemento()方法和undoFromMemento()方法,用于保存和撤销。
/**
* 发起人 (草稿)
* @author tcy
* @Date 16-09-2022
*/
public class Editor {
private String title;
private String videoUrl;
private String imgs;
public Editor(String title, String videoUrl, String imgs) {
this.title = title;
this.videoUrl = videoUrl;
this.imgs = imgs;
}
public String getTitle() {
return title;
}
public String getContent() {
return videoUrl;
}
public String getImgs() {
return imgs;
}
public void setTitle(String title) {
this.title = title;
}
public void setContent(String content) {
this.videoUrl = content;
}
public void setImgs(String imgs) {
this.imgs = imgs;
}
/**
* 保存到备忘录
* @return
*/
public VideoMemento saveToMemento(){
VideoMemento articleMemento = new VideoMemento(this.title,this.videoUrl,this.imgs);
return articleMemento;
}
/**
* 从备忘录恢复
* @param articleMemento
*/
public void undoFromMemento(VideoMemento articleMemento){
this.title = articleMemento.getTitle();
this.videoUrl = articleMemento.getContent();
this.imgs = articleMemento.getImgs();
}
@Override
public String toString() {
return "Editor{" +
"title='" + title + '\'' +
", content='" + videoUrl + '\'' +
", imgs='" + imgs + '\'' +
'}';
}
}
管理员角色(草稿箱):
包括一个栈,用于存储完稿,利用栈先进后出的特性,实现逐步的撤销。
/**
* 管理者(草稿箱)
* @author tcy
* @Date 16-09-2022
*/
public class Caretaker {
private final Stack<VideoMemento> STACK = new Stack<VideoMemento>();
public VideoMemento getMemento(){
VideoMemento videoMemento = STACK.pop();
return videoMemento;
}
public void addMemento(VideoMemento videoMemento){
STACK.push(videoMemento);
}
}
读者可以拉取完整代码到本地进行学习,实现代码均测试通过后上传到码云,本地下载。
三、总结
备忘录模式是怎么回事想必你已经明白了,如果我们在实际开发中有一个对象的功能很复杂,属性非常的多,这时候备忘录模式就是一个好的选择。
备忘录模式实现也很简单,在原对象基础之上再增加一个副本对象,在原对象上额外的增加两个方法,用于构建一个副本和从副本中取值。再创建一个栈对象,用于存储、管理副本。
备忘录模式的优势突出,会简化发起人(原对象)的职责,隔离存储状态,实现信息的封装,客户端无须关心保存细节,而且提供了状态回滚功能。
但是最显著的缺点就是消耗资源,如果对象改动较大,每一次保存都会消耗很大的内存空间,功能换空间。
备忘录模式在Jdk和Spring中应用的并不多,在我们实际应用中我们要衡量空间和效率的影响,是否使用备忘录模式进行合理的取舍。
来源:https://www.cnblogs.com/tianClassmate/p/16706597.html
猜你喜欢
- 一、判断一个字符串str不为空的方法有:1、str == null;2、"".equals(str);3、str.len
- 首先对于一个SpringBoot工程来说,最明显的标志的就是 @SpringBootApplication它标记了这是一个SpringBoo
- FrameLayout 在这个布局中,所有的子元素都不能被指定放置的位置,他们统统防御这块区域的左上角, 并且后面的子元素直接覆盖在前面的子
- 前言多数据源的事务处理是个老生常谈的话题,跨两个数据源的事务管理也算是分布式事务的范畴,在同一个JVM里处理多数据源的事务,比较经典的处理方
- requestFoucs();无效。requestFoucsFromTouch();无效。webview.setTouchListener;
- 在使用struts多模块的,找到一些小技巧和经验,与大家分享一下。 关于多module的配置就不说了,只需要用不同的config
- 前提说明之前公司有一个项目是由androidstudio接入高德地图实现导航,定位等功能,然后还有一部分登陆页面和其他逻辑都放在Unity方
- 什么是异步?为什么要用它?异步编程提供了一个非阻塞的,事件驱动的编程模型。 这种编程模型利用系统中多核执行任务来提供并行,因此提供了应用的吞
- Android 无障碍的全局悬浮窗可以在屏幕上添加 UI 供用户进行快捷操作,可以展示在所有应用程序之上长期展示。另一方面,在一些自动化场景
- C#串口模块的使用。使用VS .net框架下WinForm程序应用开发。C#开发的串口通信小工具。相比于QT添加的串口类,WinForm是通
- 效果和代码都非常直观:实例1:TimePicker<RelativeLayout xmlns:android="http:/
- 本文实例讲述了Android编程实现WebView添加进度条的方法。分享给大家供大家参考,具体如下:标准的XML界面<?xml ver
- PS:本文包含了大部分strings函数的说明,并附带举例说明。本来想自己整理一下的,发现已经有前辈整理过了,就转了过来。修改了原文一些源码
- 本文实例为大家分享了Android实现支付宝支付密码输入界面的具体代码,供大家参考,具体内容如下效果图:主要代码:import java.u
- JDK提供的流继承了四大类:InputStream(字节输入流)、OutputStream(字节输出流)、Reader(字符输入流)、Wri
- 初次安装Android Studio,遇到了不少问题,这是其中的一个,分享如下,同时求各位dalao关注一下啦((*^__^*) )使用不同
- 1、说明isInterrupted()可以判断当前线程是否被中断,仅仅是对interrupt()标识的一个判断,并不会影响标识发生任何改变(
- 模拟登陆的原理很简单,就是发送一个Http 请求服务器获得响应,然后客户端获取到cookie即可实现模拟登陆,比如一些抢票软件的原理无非也是
- 概述:Flutter中常用的滑动布局 ScrollView 有 SingleChildScrollView、NestedScrollView
- Java Function的使用一、方法介绍表示接受一个参数并产生结果的函数。参数类型 T - 函数输入的类型R - 函数的结果类型方法介绍