惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Webroot Blog
Webroot Blog
U
Unit 42
A
About on SuperTechFans
宝玉的分享
宝玉的分享
月光博客
月光博客
C
CERT Recently Published Vulnerability Notes
P
Privacy International News Feed
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
P
Privacy & Cybersecurity Law Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
Securelist
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
Apple Machine Learning Research
Apple Machine Learning Research
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
B
Blog
I
Intezer
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
V
V2EX
L
LangChain Blog
AI
AI
G
GRAHAM CLULEY
T
Tor Project blog
人人都是产品经理
人人都是产品经理
D
Docker
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
I
InfoQ
Y
Y Combinator Blog
C
Comments on: Blog
GbyAI
GbyAI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
aimingoo的专栏
aimingoo的专栏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
H
Help Net Security
Vercel News
Vercel News
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
爱范儿
爱范儿

博客园 - 网络金领

C# WinForm 导出导入Excel/Doc 完整实例教程[使用Aspose.Cells.dll] DataTable的数据批量写入数据库 C# .NET锁屏程序(顺带屏蔽任务管理器) 步步为营 .NET 代码重构学习 十一 - 网络金领 步步为营 .NET 代码重构学习笔记 十 步步为营 .NET 代码重构学习笔记 九 步步为营 .NET 代码重构学习笔记 八 步步为营 .NET 代码重构学习笔记 七 步步为营 .NET 代码重构学习笔记 六、移动函数和移动值域(Move Method And Move Field) 步步为营 .NET 代码重构学习笔记 五、分解函数和替换算法(Replace Method And Substitute Algorithm) 步步为营 .NET 代码重构学习笔记 四、临时变量(Temporary Variable) 步步为营 .NET 代码重构学习笔记 二、提炼方法(Extract Method) 步步为营 .NET 代码重构学习笔记 三、内联方法(Inline Method) 步步为营 .NET 代码重构学习笔记 一、为何要代码重构 步步为营 .NET 设计模式学习笔记 二十四、Factory Method(工厂方法模式) 步步为营 .NET 设计模式学习笔记 二十三、Interpreter(解释器模式) 步步为营 .NET 设计模式学习笔记 二十一、Visitor(访问者模式) 步步为营 .NET 设计模式学习笔记 二十、Mediator(中介者模式) 步步为营 .NET 设计模式学习笔记 十九、Chain of Responsibility(职责链模式)
步步为营 .NET 设计模式学习笔记 二十二、Memento(备望录模式)
网络金领 · 2011-06-01 · via 博客园 - 网络金领

概述

在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。

意图

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

结构图

image

角色说明:

Memento(备忘录):保存Originator对象的内部状态(主动权在Originator),提供宽接口给Originator,提供窄接口给CareTaker。
Originator(原发器):控制那些内部状态要保存,防止外界对象访问Memento,自己可以访问Memento,尤其是先前状态。
CareTaker:负责保存Memento,但不能浏览Memento(从而是窄接口)。
State:状态类,用来模拟内部状态,亦可以是一个string,这里设计成类更有一般意义。

生活中的例子

在使用IE浏览器时,有一个按扭返回上一步操作,返回上一个打开的页面,其实原理和备望录模式一样.

用例示例图

实现一个用户信息保存的功能,用例图如下:

image

代码设计

先创建UserInfo.cs:

03     private string _Name;
04     private string _Address;
06     public string Name
08         get { return _Name; }
09         set { _Name = value; }
12     public string Address
14         get { return _Address; }
15         set { _Address = value; }
21     /// <param name="name"></param>
22     /// <param name="address"></param>
23     public UserInfo(string name, string address)
25         this._Name = name;
26         this._Address = address;
32     /// <param name="memento"></param>
33     public void setMemento(Memento memento)
35         this._Name = memento.Name;
36         this._Address = memento.Address;
42     /// <returns></returns>
43     public Memento CreateMemento()
45         return new Memento(this.Name, this.Address);
48     public string ShowInfo()
50         return string.Format("My name is {0} , my address in {1}. \n", this.Name, this.Address);

再创建Memento.cs:

03     private string _Name;
04     private string _Address;
06     public string Name
08         get { return _Name; }
09         set { _Name = value; }
12     public string Address
14         get { return _Address; }
15         set { _Address = value; }
18     public Memento(string name, string address)
20         this._Name = name;
21         this._Address = address;

再创建SaveMemento.cs:

01 public class SaveMemento
03     private Memento _memento;
05     public Memento TheMemento
07         set { _memento = value; }
08         get { return _memento; }
11     public SaveMemento(Memento memento)
13         this._memento = memento;

最后再调用

01 public partial class Run : Form
05         InitializeComponent();
08     private void btnRun_Click(object sender, EventArgs e)
10         //-------------------------------------
11         UserInfo user = new UserInfo("spring yang", "ningbo");
12         rtbResult.AppendText(user.ShowInfo());
13         SaveMemento memento = new SaveMemento(user.CreateMemento());
14         user.Name = "zhangshang";
15         user.Address = "xanghai";
16         rtbResult.AppendText(user.ShowInfo());
17         user.setMemento(memento.TheMemento);
18         rtbResult.AppendText(user.ShowInfo());

运行结果如下图:

image

实现要点

1.备忘录(Memento)存储原发器(Originator)对象的内部状态,在需要时恢复原发器状态。Memento模式适用于“由原发器管理,却又必须存
储在原发器之外的信息”
2.在实现Memento模式中,要防止原发器以外的对象访问备忘录对象。备忘录对象有两个接口,一个为原发器使用的宽接口;一个为其他对象使用
的窄接口。
3.在实现Memento模式时,要考虑拷贝对象状态的效率问题,如果对象开销比较大,可以采用某种增量式改变来改进Memento模式。

优点

1.有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。

2.本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需要的这些状态的版本。

3.当发起人角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。

缺点

1.如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。

2.当负责人角色将一个备忘录 存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。

3.当发起人角色的状态改变的时候,有可能这个协议无效。如果状态改变的成功率不高的话,不如采取“假如”协议模式。

适用性

1.必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
2.如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

总结

主要用于保存操作先前状态的信息.