前言
不知诸君有没有看过在下写的命令模式实现操作前进和回滚的文章,其实备忘录模式的主要目的也是这个,但是实现的方式不同,这里将讲解一下这两种方式的区别。
1.备忘录实现回滚和前进
没有看过命令模式实现操作前进和回滚的,建议去看看,传送门:https://blog.csdn.net/m0_37920739/article/details/104428753 看完以后,又看过其他网站写的备忘录模式,可能现在会比较晕,不知道内心是否再想命令模式实现和备忘录模式实现到底有何区别啊?
备忘录模式偏向的是保存改变前的状态,而命令模式是保存有前进和回滚功能的对象。所以将军莫虑,且看此码,接下来用备忘录模式去替换一下命令模式实现P图软件的回滚前进,具体代码如下:
public struct Point
{
public int x;
public int y;
}
public struct Size
{
public uint width;
public uint height;
}
public enum Color
{
white,
black,
red,
green,
blue,
}
public static class Globe
{
public static Recorder<PictureObject> picRecorder = new Recorder<PictureObject>();
}
public class LoadPicMgr
{
public static readonly LoadPicMgr instance = new LoadPicMgr();
public byte[] Load(string picturePath)
{
Console.WriteLine("加载图片路径:"+picturePath);
return new byte[0];
}
}
public class PictureObject
{
private string picturePath;
private byte[] pictureDataBytes;//图片的实际数据
public PictureObject(string picturePath)
{
this.picturePath = picturePath;
pictureDataBytes = LoadPicMgr.instance.Load(picturePath);
}
public PictureObject Clone()
{
return (PictureObject)MemberwiseClone();
}
}
public class Recorder<T>
{
private int index = 0;
private List<T> saveNodes = new List<T>();
public void Save(T picObject)
{
//如果回滚到某个节点,再执行笔刷或者油漆桶操作,后面节点全部销毁
saveNodes.RemoveRange(index+1,saveNodes.Count);
saveNodes.Add(picObject);
index = saveNodes.Count;
}
public void Reset()
{
saveNodes.Clear();
}
public T Forward()
{
if (index + 1 < saveNodes.Count)
{
index++;
return saveNodes[index];
}
return default(T);
}
public T Back()
{
if (index - 1 >= 0)
{
index--;
return saveNodes[index];
}
return default(T);
}
}
public class EraserModule
{
public Size size;
public Point point;
public int layer;
public static EraserModule instance = new EraserModule();
public void DoEraser(PictureObject pictureObject)
{
Globe.picRecorder.Save(pictureObject.Clone());//要改变状态了,先保存之前的状态
Console.WriteLine("执行操作层级:" + layer);
}
}
public class PaintModule
{
public Color color;
public Size size;
public Point point;
public int layer;
public static PaintModule instance = new PaintModule();
public void DoPaint(PictureObject pictureObject)
{
Globe.picRecorder.Save(pictureObject.Clone());//要改变状态了,先保存之前的状态
Console.WriteLine("执行操作层级:" + layer);
}
}
public class BrushModule
{
public Color color;
public int depth;
public int layer;
public static BrushModule instance = new BrushModule();
public void DoBrush(PictureObject pictureObject)
{
Globe.picRecorder.Save(pictureObject.Clone());//要改变状态了,先保存之前的状态
Console.WriteLine("执行操作层级:" + layer);
}
}
可以看到比起命令模式,去掉了所有Order相关类,在执行改变操作之前都先Globle.picRecorder.Save(pictureObject.Clone());所以看到这里大概有点头绪了,接下来将用图详解分析一下到底什么情况下用命令模式或者用备忘录模式。
2.命令和备忘录区别
相比于备忘录模式而言,命令模式更加难以实现而且每一个操作都要将它封装成对象,给大家打个比方,为什么命令模式去实现P图软件的操作前进和回滚比较难,因为操作回滚命令比较难写,比如在图片上画了一笔,要执行回滚操作的话,一般的思想就是把被覆盖的数据提前缓存下来,然后回滚时去进行替换。所以命令模式增加很多复杂的过程,具体图片详解如下:
备忘录模式保存了对象改变前的整体状态,比如图片要执行画笔操作之前,先把图片原样保存一份。所以不管到底操作过程是什么,只要图片状态即将发生变化就马上把它生前的样子拷贝下来,具体图片详细如下:
难道命令行模式去实现此功能就如此不堪嘛?假设图片很大是10M,使用备忘录模式,相当于执行一次操作就保存了10M左右的副本,可能就简简单单p个图,内存就暴增到几个G(当然这里没有考虑到备忘录模式的优化,比如只保存修改前的区域数据,然后回滚的时候将此区域进行替换即可,而不是全部保存下来。但是又存在前进功能,所以还要保存修改后的区域数据),所以命令模式去实现这个功能虽然很麻烦但是还是有优点的,只不过回滚和前进要执行一遍操作函数,而不是简简单单的把当前对象引用替换成已经保存好的副本,性能方面备忘录模式表现的更加优秀,内存占用方面命令模式表现的更加优秀。最后的最后!!!吾已诚心相献,奈何踌躇不前,希望大家感觉有帮助的就点赞啦。
总结
1.备忘录模式优缺点
优点: 1、提供一种恢复状态的机制,可以方便地回到某个历史状态。 2、用户不必关心保存的细节,实现信息封装。
缺点:如果类的成员变量过大,势必会占用比较大的内存资源。
2.备忘录模式使用场景
1.浏览器的回滚和前进
2.P图软件的回滚和前进。
3.单机游戏中需要的游戏存档列表。