Design Pattern for Undo Engine
I'm creating an architectural modeling device for a civil enginering application. I have one massive version class standing for the whole structure, that include collections of nodes, line components, lots, etc which are additionally personalized courses.
I have actually currently coded an undo engine which conserves a deep - duplicate after each alteration to the version. Currently I began assuming if I can have coded in different ways. As opposed to conserving the deep - duplicates, I can probably conserve a checklist of each modifier activity with an equivalent reverse modifier. To make sure that I can use the reverse modifiers to the existing version to undo, or the modifiers to remodel.
I can visualize just how you would certainly execute straightforward commands that transform object buildings, etc But just how around intricate commands? Like putting new node challenge the version and also including some line things which maintain referrals to the new nodes.
Just how would certainly one deal with applying that?
I'm with Mendelt Siebenga on the reality that you need to make use of the Command Pattern. The pattern you made use of was the Memento Pattern, which can and also will certainly come to be really inefficient with time.
Given that you are working with a memory - extensive application, you need to have the ability to define either just how much memory the undo engine is permitted to occupy, the amount of degrees of undo are conserved or some storage space to which they will certainly be lingered. Need to you refrain this, you will certainly quickly encounter mistakes arising from the equipment running out memory.
I would certainly suggest you examine whether there is a structure that currently developed a version for undos in the shows language / structure of your selection. It behaves to design new things, yet it is far better to take something currently created, debugged and also examined in actual circumstances. It would certainly aid if you included what you are creating this in, so individuals can advise structures they recognize.
I've applied facility undo systems sucessfully making use of the Memento pattern - really simple, and also has the advantage of normally giving a Redo structure also. An extra refined advantage is that accumulated activities can be had within a solitary Undo also.
In short, you have 2 heaps of memento things. One for Undo, the various other for Redo. Every procedure develops a new token, which preferably will be some phone call to transform the state of your version, record (or whatever). This obtains included in the undo pile. When you do an undo procedure, along with implementing the Undo activity on the Memento challenge transform the version back once more, you additionally pop the object off the Undo pile and also push it appropriate onto the Redo pile.
Just how the method to transform the state of your record is applied depends entirely on your execution. If you can merely make an API call (as an example ChangeColour (r, g, b) ), after that precede it with a question to get and also conserve the equivalent state. Yet the pattern will certainly additionally sustain making deep duplicates, memory photos, temperature documents production etc - it is all approximately you as it is is merely a digital method execution.
To do accumulated activities (as an example customer Shift - Selects a load of challenge do a procedure on, such as delete, relabel, transform feature), your code develops a new Undo pile as a solitary token, and also passes that to the real procedure to add the specific procedures to. So your activity approaches do not require to (a) have an international pile to bother with and also (b) can be coded the very same whether they are implemented alone or as component of one accumulation procedure.
Several undo systems remain in - memory just, yet you can linger the undo pile out if you desire, I presume.
As others have actually mentioned, the command pattern is a really effective method of applying Undo/Redo. Yet there is necessary benefit I would love to state to the command pattern.
When applying undo/redo making use of the command pattern, you can stay clear of huge quantities of copied code by extracting (somewhat) the procedures executed on the information and also make use of those procedures in the undo/redo system. As an example in a full-screen editor cut and also paste are corresponding commands (in addition to the monitoring of the clipboard). To put it simply, the undo procedure for a cut is paste and also the undo procedure for a paste is reduced. This relates to much less complex procedures as keying and also removing message.
The key below is that you can utilize your undo/redo system as the key command system for your editor. As opposed to creating the system such as "create undo object, change the document" you can "create undo object, execute remodel procedure on undo challenge change the document".
Currently, unquestionably, many individuals are believing to themselves "Well duh, isn't component of the factor of the command pattern?" Yes, yet I've seen way too many command systems that have 2 collections of commands, one for prompt procedures and also an additional set for undo/redo. I'm not claiming that there will not be commands that specify to prompt procedures and also undo/redo, yet lowering the replication will certainly make the code extra maintainable.
We recycled the documents load and also conserve serialization code for “objects" for a hassle-free kind to conserve and also recover the whole state of an object. We push those serialized things on the undo pile-- in addition to some details concerning what procedure was executed and also tips on undo - ing that procedure if there is n`t adequate details amassed from the serialized information. Undo and also Redoing is usually simply changing one object with an additional (theoretically).
There have actually been several MANY pests as a result of reminders (C+npls) to things that were never ever dealt with - up as you execute some weird undo remodel series (those areas not upgraded to more secure undo mindful “identifiers"). Pests around usually
Some procedures can be grandfather clauses for speed/resource use - like sizing points, relocating points about.
Multi - option gives some intriguing difficulties too. Luckly we currently had an organizing principle in the code. Kristopher Johnson comment concerning below - things is rather close to what we do.
Just read concerning the command pattern in my dexterous growth publication - possibly that is obtained possibility?
You can have every command implement the command user interface (which has an Execute() method). If you desire undo, you can add an Undo method.
extra details here
I needed to do this when creating a solver for a fix - dive problem video game. I made each action a Command object that held adequate details that maybe either done or reversed. In my instance this was as straightforward as saving the beginning placement and also the instructions of each action. I after that saved all these things in a pile so the program can conveniently undo as several actions as it required while backtracking.
Most instances I've seen make use of a version of the Command-Pattern for this. Every customer - activity that is undoable obtains its very own command instance with all the details to execute the activity and also roll it back. You can after that keep a checklist of all the commands that have actually been implemented and also you can roll them back individually.
I as soon as worked with an application in which all adjustments made by a command to the application is version (i.e, CDocument. we were making use of MFC) were lingered at the end of the command by upgrading areas in an inner data source kept within the version. So we did not need to write different undo/redo code for each and every activity. The undo pile merely bore in mind the key keys, area names and also old values every single time a document was transformed (at the end of each command).