二十三种设计模式[18] - 备忘录模式(Memento Pattern)
前言?????? 在日常生活中我们经常会接触到类似回滚或撤销的功能,比如单机游戏中的存档、windows中的备份/恢复、手机的恢复出厂设置以及编辑器中的撤销功能。本质上这些功能都是将系统某个瞬间的状态备份,以便在需要时将系统恢复至备份的状态。而备忘录模式就是一种帮助我们实现这一系列操作的设计模式。 ?????? 备忘录模式又名快照模式,对象行为型模式的一种。在《设计模式 - 可复用的面向对象软件》一书中将之描述为“ 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态 ”。 结构
?????? 在备忘录模式中,一个备忘录是一个对象,它是一个用来存储另一对象在某个瞬间的状态的类,而后者则称为该备忘录的原发器或发起人。为了保证原发器的封装性,备忘录中存储的数据只能由原发器访问,而负责人只能对备忘录进行存储和传递操作。在《设计模式》一书中表示,备忘录对外部对象提供了两个接口,分别是只能存储和传递对象的窄接口以及可以访问备忘录中存储的所有数据的宽接口。 示例public interface IMemento { } public class Originator { public string State { set; get; } = string.Empty; public IMemento CreateMemento() { return new Memento(this.State); } public void Restore(IMemento obj) { var memento = obj as Memento; if(memento == null) { throw new TypeLoadException(); } this.State = memento.State; } private class Memento : IMemento { public string State { set; get; } = string.Empty; public Memento(string state) { this.State = state; } } } public class Caretaker { public IMemento Memento { set; get; } = null; } static void Main(string[] args) { Originator originator = new Originator(); originator.State = "v1"; Caretaker caretaker = new Caretaker(); caretaker.Memento = originator.CreateMemento(); originator.State = "v2"; Console.WriteLine($"[Originator.State]:{originator.State}"); originator.Restore(caretaker.Memento); Console.WriteLine($"[Originator.State]:{originator.State}"); Console.ReadKey(); } ?????? 在结构中提到,为了不破坏原发器的封装性,需要对备忘录存储的数据做出一定的访问限制。示例中的做法是将备忘录Memento类作为原发器Originator类的内部类,Memento实现了一个不做任何定义的接口IMemento作为暴露给负责人的类型,使负责人不能对备忘录的内部数据做出操作。
?????? 命令模式(Command Pattern)的应用场景之一是实现一个可撤销的操作。备忘录模式与命令模式的组合使用,可以使撤销操作的职责更明确。如下。 public interface IMemento { } public class Originator { public string State { set; get; } = string.Empty; public IMemento CreateMemento() { return new Memento(this.State); } public void Restore(IMemento obj) { var memento = obj as Memento; if(memento == null) { throw new TypeLoadException(); } this.State = memento.State; } private class Memento : IMemento { public string State { set; get; } = string.Empty; public Memento(string state) { this.State = state; } } } public class ChangeStateCommand { private Originator OriginatorObj { set; get; } = null; private IMemento MementoObj { set; get; } = null; public ChangeStateCommand(Originator originator) { this.OriginatorObj = originator; } public void Execute(string state) { this.MementoObj = this.OriginatorObj.CreateMemento(); this.OriginatorObj.State = state; } public void Undo() { this.OriginatorObj.Restore(this.MementoObj); } } static void Main(string[] args) { Originator originator = new Originator(); ChangeStateCommand command = new ChangeStateCommand(originator); command.Execute("v1"); command.Execute("v2"); Console.WriteLine($"[Originator.State]:{originator.State}"); command.Undo(); Console.WriteLine($"[Originator.State]:{originator.State}"); Console.ReadKey(); } ?????? 在与命令模式组合使用时,我们将命令类看做负责人来存储原发器的内部状态,示例中在执行ChangeStateCommand类中的Execute函数时备份Originator的内部状态以便在执行Undo函数时恢复。 总结?????? 备忘录模式给我们提供了一种可以恢复对象的机制,能够方便我们将某一对象回退至某一瞬间的状态。也在某种程度上简化了原发器的设计,使原发器不必为了回滚机制而保留一些与之无关的引用。如果原发器在生成备忘录时必须存储大量的信息或客户非常频繁的创建备忘录和恢复原发器时会导致非常大的内存开销。 ?????? 以上,就是我对备忘录模式的理解,希望对你有所帮助。 ?????? 示例源码:https://gitee.com/wxingChen/DesignPatternsPractice ?????? 系列汇总:https://www.cnblogs.com/wxingchen/p/10031592.html ?????? 本文著作权归本人所有,如需转载请标明本文链接(https://www.cnblogs.com/wxingchen/p/10101563.html) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- windows-server-2008 – 如果我没有指定密码,为什么PSEXEC会
- 从命令行在Windows上查找CPU时间
- Windows 7上的XAMPP无法正常工作
- Windows 10工程版本泄露全新设计的操作中心圆角样式
- windows-server-2008 – 更改Windows SID如何影响SQL Serve
- window.print()JavaScript的特征检测解决方案
- 在WIndows 7中使用带有英特尔高清显卡的OpenCL入门
- winapi – Windows API中有哪些定期计时器对象?
- Windows – 终端服务器/ Citrix XenApp替代方案?
- windows-server-2012 – 如何在Windows Server 2012中为IIS