Pergunta

In a drawing application, I'm implementing multi-level undo/redo using Memento pattern. One problem that I was facing was that the memento (the state object) would become too large if the drawing contains one or more image objects (my drawing object can have base64-encoded image objects embedded in it, just like Visual Studio's resx files), which would make the undo/redo stacks to climb to several megabytes soon because of the frequent mouse operations that are common in drawing apps. To solve this problem, I introduced gzip compression into it so that I now saved a zipped version of the memento onto the stack. This resulted in about 90% reduction in the overall stack size.

Now this has resulted in another problem. The time it takes to zip / unzip a memento has introduced considerable jags in object positioning/resizing.

One way to solve this is to use Command pattern, but I'm reluctant to go that path becuz it will introduce a whole lot of work in many parts of the application. What other alternates do you see?

Foi útil?

Solução

The only solution I can think of without switching entirely to the Command pattern is to generate a kind of incremental backup of the object as a memento instead of using the whole object.

The idea is that you would strip from the memento any data that haven't changed. You would then only store the difference.

When doing an undo, you would use the current state of the object and the difference to generate a memento and inject it in the process.

Here's basically how it will look like:

  1. The caretaker is going to do something to the originator, but wants to be able to undo the change.
  2. The caretaker first asks the originator for a memento object.
  3. Then it does whatever operation (or sequence of operations) it was going to do.
  4. A compressor will compare the memento and the new state of the originator and generate a diff object which will be stored on the operation stack

To undo:

  1. The compressor will recreate a memento object from the originator state and the diff object
  2. The new memento is then used to restore the originator state.

The implementation of the compressor class might be tricky and will depend on the type of operations you will perform.

You will be using one single memento object and store only the diff objects which can also be compressed if needed but will probably be rather small.

Outras dicas

When I did something similar in Delphi way back in the 90s I took snapshots, i.e. bitmaps of the current state, whenever the redraw got too slow, after lots of draw actions on the stack/queue/list. Not sure if you can do that, though.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top