Memento Pattern in Actionscript 3 (UNDO/REDO)

Happy new Year everybody!

I’d like to begin 2010 with a design pattern argument.

First design pattern of this year is Memento pattern, that could be very useful if you are working on an AIR desktop application or in a Flex RIA and you want to make an history of user’s actions.
In fact this pattern is used to make undo and redo in an application.

Memento pattern is tightly coupled with originator object and it’s usually composed by 3 different parts:

  • memento
  • caretaker
  • originator

Originator is object that pass data to caretaker and it saved them in a couple of arrays (undoArray and redoArray).
So caretaker is an object that stores a memento snapshot and, if originator needs, pass undo or redo data to this object.

I prepare a sample to understand better what could you use Memento pattern in your applications (“view source” option is activated).
I wrote a Memento class with a Singleton to centralize all users actions,then I create a MementoVO that is a dynamic class to help me store data from each object used by the user, you could use a simple Object instead of a dynamic class to save more memory if you prefer.
Sample is very easy but useful for Memento pattern purpose, in fact you can move windows trough the stage and our “history” class (Memento.as) saves their positions when saveAction method is called by the originator (an instance of CustomWin).

Memento class has 4 essentials methods that are:

  • undo()
  • redo()
  • saveAction(_obj:Object)
  • saveRedoAction(_obj:Object)

I start from the end, saveRedoAction, last method, is used to save the position of a window before I restore its positions, usually Redo action is used only one time, but if you want you could create an Array and work with multiple Redo.

Another important method is saveAction that is called when mouse down event was triggered and it stores in memento class own old position and object itselfs.

First two methods need to undo and redo an user action, it’s easy isn’t it?!

I think that in this year I’ll share lots of those patterns with you to share our knowledge together so feel free to add comment at this post and we could make an interesting and useful conversation, I’m totally sure!

Advertisement

Published by

luca mezzalira

Being associated with the industry since 2004, I have lent my expertise predominantly in the solution architecture field. I have gained accolades for revolutionising the scalability of frontend architectures with micro-frontends, from increasing the efficiency of workflows, to delivering quality in products. My colleagues know me as an excellent communicator who believes in using an interactive approach for understanding and solving problems of varied scopes. I helped DAZN becoming a global streaming platform in just 5 years, now as Principal Architect at AWS, I'm helping our customers in the media and entertainment space to deliver cost-effective and scalable cloud solutions. Moreover, I'm sharing with the community the best practices to develop cloud-native architectures solving technical and organizational challenges. My core industry knowledge has been instrumental in resolving complex architectural and integration challenges. Working within the scopes of a plethora of technical roles such as tech lead, solutions architect and CTO, I have developed a precise understanding of various technicalities which has helped me in maximizing value of my company and products in my current leadership roles.

10 thoughts on “Memento Pattern in Actionscript 3 (UNDO/REDO)”

  1. I think it’s great that you’re sharing examples like this with the world and encourage you to continue! However, if you’ll permit me, I feel the need to point out that the implementation you described does not match that formal definition of the Memento pattern. For example, the Memento pattern dictates that the Memento object (MomentoVO in your example) should expose no public interface to the Caretaker. In other words, the Caretaker should not be able to read or write any Memento properties. Also, the Originator should be responsible for constructing, populating, and returning new Memento instances to the Caretaker, typically through a “getState()” method (hence the name “Originator”). There are a few other things slightly odd about your implementation. Consider reviewing the formal pattern in the Gang of Four book or on Wikipedia. Also look into the Command pattern which is often used to implement undo/redo functionality and which your implementation has some similarity to.

    Cheers!

    1. Hi Kristopher,
      I’m totally agree with you and is a good point your explanation, I really appreciate a lot.
      I know what are you saying, I’m starting with this sample and now I’m working on same sample
      that runs with PureMVC too. So when will be ready I’ll share that one too and this time I’ll write in more formal way.
      Thank you again for your contribute

  2. In your application, when you undo and then redo, the last state doesn’t seem to be calculated. For example, move an object twice. Then undo twice. Now redo twice. Only one redo operation will occur…

  3. hi, i tried use your idea in my project, i have some problem..
    code in my component(originator)
    ..
    class MyComp extends Group

    addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
    var obj:Object = new Object();
    obj.who = this;
    obj.x = x;
    obj.y = y;
    obj.rotation = rotation;
    obj.alpha = alpha;
    memento.saveAction(obj);
    });

    in another class

    public function undo():void {
    var tMem:MementoVO = Memento.getInstance().undo();
    if(null != tMem) {
    var myComp:MyComp = tMem.who as MyComp;
    Alert.show(getQualifiedClassName(tMem.who as MyComp));
    //this Alert will show ‘null’
    Alert.show(getQualifiedClassName(tMem.who));
    //this Alert will show ‘global’
    }
    }

    that results is not right, and i can`t use for example myComp.x or myComp.y properties.
    thanks!

  4. that code is works ok,
    addEventListener(MouseEvent.MOUSE_DOWN, func);
    ..
    private function func(e:Event):void {
    //in this function ‘this’ is visible
    }

    in case that code
    addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
    // ‘this’ is not visible, only ‘global’
    });

    thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s