做商铺的网站有那些,成都必去的10个景点,专业app软件定制,网页设计网站建设的基本流程需求
撤销与重做功能
思考
关于记录的数据的两点思考#xff1a;
记录操作记录影响显示和逻辑的所有数据
很显然这里就要考虑取舍了#xff1a; 记录操作 这种方案只需要记录每一步的操作#xff0c;具体这个操作要怎么渲染和实现出来完全需要自己去实现#xff0c;这…需求
撤销与重做功能
思考
关于记录的数据的两点思考
记录操作记录影响显示和逻辑的所有数据
很显然这里就要考虑取舍了 记录操作 这种方案只需要记录每一步的操作具体这个操作要怎么渲染和实现出来完全需要自己去实现这种方式的好处是记录的数据量比较小节省内存但业务逻辑复杂适合复杂庞大的数据记录 记录影响显示的所有数据 这种方案要记录所有影响显示和逻辑的所有数据无疑这种数据量肯定是比第一种大的内存占用会比较大但是业务逻辑简单
这里由于我的数据量不大所以选择了第二种方式来进行处理
首先肯定要有一个Manager来负责管理数据并实现撤销和重做的分发我命名为UndoManager还要有一个数据对象来记录每一步的数据,由于需要记录的信息未知可能是一个json也可能是一个对象所以这里用最抽象的接口来表示每一步的数据信息后续怎么处理这份数据完全根据项目需求自己定制我命名为IRecordData
Redo Undo的功能都是先进后出的数据结构这种数据结构对应到程序世界的话刚好对应的是Stack,这里就先用Stack来进行思考 定义有两个Stack 分别是UndoStack 和 RedoStack 分别来存储待撤销记录和待重做记录假设这两个Stack的当前状态如下 假设这个时候来个一个新的步骤Step4 这个时候Step4需要记录记录的过程如下 假设我现在需要撤销一步回到Step3,具体过程如下
假设现在我又想重做上一步想回到Step4,具体过程如下 至此我们的记录、撤销、重做的核心逻辑就已经基本梳理清楚了但是发现Record还有一个小问题,问题如下 当我们RedoStack中存在数据时如果记录新的步骤Step4,成功之后我们会发现现在Undo会回到Step1,Redo会回到Step2,这样流程就乱了所以修改一个Record的逻辑修改后如下 有两种处理方案方案一为每次记录新数步骤时清空RedoStack方案二为每次记录新数据时将RedoStack中的数据尽数移动到UndoStack中可根据需求选择。
由于我们选择的数据记录是记录影响显示和逻辑的所有数据 本身内存占用就比记录操作要大如果再对这两个Stack的容量不做限制就可能会浪费很多的内存导致程序内存占用过高。所以我们需要对UndoStack和RedoStack做容量限制超过容量时最早进入Stack的数据直接丢弃但Stack本身是先进后出的数据结构显然不能支持这种操作所以权衡利弊之后我选择将Stack改为LinkedList具体的操作流程是一样的。
实现
下面直接展示源码
using System.Collections.Generic;namespace S
{public interface IRecordData{}public class UndoManager{private LinkedListIRecordData undoLinkedList;private LinkedListIRecordData redoLinkedList;private IRecordData currentData;/// summary/// Undo数量/// /summarypublic int undoCount undoLinkedList null ? 0 : undoLinkedList.Count;/// summary/// Redo数量/// /summarypublic int redoCount redoLinkedList null ? 0 : redoLinkedList.Count;/// summary/// 记录的最大容量 0时 代表无限容量/// /summarypublic int maxCount0;public UndoManager(){undoLinkedList new LinkedListIRecordData();redoLinkedList new LinkedListIRecordData();currentData null;}/// summary/// 重做一步/// /summary/// returns/returnspublic IRecordData Redo(){if (currentData ! null){undoLinkedList.AddLast(currentData);}if (redoLinkedList.Count 0){currentData null;}else{currentData redoLinkedList.Last.Value;redoLinkedList.RemoveLast();}return currentData;}/// summary/// 撤销一步/// /summary/// returns/returnspublic IRecordData Undo(){if (currentData ! null){redoLinkedList.AddLast(currentData);}if (undoLinkedList.Count 0){currentData null;}else{currentData undoLinkedList.Last.Value;undoLinkedList.RemoveLast();}return currentData;}/// summary/// 记录/// /summary/// param namerecordData记录对象/param/// param nameoverrideRedo是否覆盖Redo链表/parampublic void Record(IRecordData recordData,bool overrideRedotrue){if (currentData ! null){undoLinkedList.AddLast(currentData);}if (overrideRedo){redoLinkedList.Clear();}else{while (redoLinkedList.Last ! null){IRecordData value redoLinkedList.Last.Value;redoLinkedList.RemoveLast();undoLinkedList.AddLast(value);}}currentData recordData;if (maxCount0undoCount maxCount) //容量维护{undoLinkedList.RemoveFirst();}}/// summary/// 清空undoredo/// /summarypublic void Clear(){undoLinkedList.Clear();redoLinkedList.Clear();}}
}