ActionScript 3.0 Memento Design Pattern: Encapsulating Saved States

The Undo Pattern

One of my most-used keyboard combinations is Ctrl+Z to undo just about anything from a program line of code to a graphic drawing. Fortunately for all of us, we can undo just about anything and get back to a state where things were okay—or at least not as bad. The Memento Design Pattern is designed to save state without violating encapsulation. Violating encapsulation could be a problem because encapsulation helps insure the application’s reliability and extensibility. Saving state in itself is pretty simple—just dump the state’s value into a variable, array or object and retrieve it when you need it. However, doing so exposes the state to other objects that might affect it in ways you cannot control.

An Enigma

While the purpose of the Memento is about as clear as you can get, it’s implementation was somewhat of an enigma to me. First, it is one of only three patterns that do not have an interface or abstract class participants (the Singleton and Facade are the others). I suppose that’s not that big of a deal, but those participants in the pattern always seemed to be the glue that holds everything together. That does not mean that the Memento pattern has no interfaces; just not classes identified as such. (More on this further on.) Second, in looking at every Memento design I could find, they seemed to be all over the map—including a couple that added interface participants in the pattern. Like most patterns, I like to begin with a minimalist example to reveal its structure. Also, I like to stick very close to The Gang of Four’s structure; so part of the problem is probably my inherent conservatism when it comes to design patterns. Some of the Memento examples I looked at had me hard-pressed to believe that they were actually Mementos as described by Gamma and his associates. Everyone likes the undo idea, but I’m not so sure that they implement their Mementos with the kind of state encapsulation envisioned by the pattern’s architects.

Sticking Close to the Memento

To get started, take a look at the Memento class diagram. I included labels in red for the nature of the relations between the three main classes and the dog-eared boxes as well:
Memento Class Diagram
Figure 1:Memento Class Diagram

The Gang of Four describes the interfaces in terms of the relations between the three participants as wide and narrow relative to the Memento class. First, the Caretaker class acts like a guardhouse storing the mementos and keeping them from other objects giving it a narrow interface to the Memento class. Second, the Originator has a wide interface so that it can restore itself to a previous state and create mementos that will save a given state.

My ultimate goal is to take an application that coordinates a video and movie clips for an online learning experience. The user can decide in the middle of a lesson to go somewhere else, and no matter where she goes, her previous place (state) will be resumed as soon as she decides to come back. For example, she might decide to go back over some earlier material to check something and then return to her current place. Actually, this is a pretty simple application using the Memento because it only saves a single previous state with two dimensions.One dimension is the place in the video and the other dimension is the accompanying movie clip. As long as those two states can be preserved, any previous paths are ignored beyond a single step back and return.

For an abstract example of the Memento in use, however, I decided to go with an array that can save multiple steps—states. I also tried an associative array, and that worked fine, but for this example I couldn’t resist the stack nature of arrays because they can be viewed as a trail of bread crumbs of past states.

A Minimalist Abstract Memento

In looking at the class diagram, you can see the three participants in the class: The Originator, Memento and Caretaker. The originator creates mementos to store a state. This is done by creating a memento and setting the state as a function of a memento getter. The memento stores the internal state of the originator, and the caretaker, with a narrow interface to the memento and only pass the memento. The structure both stores and retrieves states safe from other objects. The following example uses the same terms for both the classes and the operations as the Class Diagram.

package 
{
	public class Originator
	{
		private var mstate:String;
 
		public function setState (mstate:String):void
		{
			trace ("Setting state to: "+mstate);
			this.mstate=mstate;
		}
 
		public function createMemento ():Memento
		{
			trace ("Creating memento with current state");
			return new Memento(mstate);
		}
 
		public function setMemento (m:Memento)
		{
			mstate=m.getState();
			trace ("State of originator after getting memento:"+mstate);
		}
	}
}

The trace() statements in the class help to show the changing states and what happens when the different methods act on them. The Memento class shows a very simple set of getters and setters for preserving the states as you can see in the following code listing:

package 
{
	public class Memento
	{
		private var mstate:String;
 
		//SetState()
		public function Memento (stateSetter:String)
		{
			mstate=stateSetter;
		}
		//GetState()
		public function getState ():String
		{
			return mstate;
		}
	}
}

The final class of the Memento trio is the Caretaker. Notice how it aggregates the Memento class.

package 
{
	public class Caretaker
	{
		private var storage:Array;
 
		public function Caretaker()
		{
			storage=new Array();
		}
 
		public function addMemento (m:Memento):void
		{
			storage.push (m);
		}
 
		public function getMemento (index:int):Memento
		{
			return storage[index];
		}
	}
}

To test the class, I created a SaveState class. You could use the Originator for generating values, but I like the idea that the Memento can stand as a structure for any application. So in reality, the SaveState class is really any client that may want to use the Memento for saving and retrieving its state.

package 
{
	import flash.display.Sprite;
	public class SaveState extends Sprite
	{
		private var ct:Caretaker;
		private var orig:Originator;
 
		public function SaveState ()
		{
			ct=new Caretaker();
			orig= new Originator();
 
			orig.setState ("First Step");
			ct.addMemento (orig.createMemento());
			orig.setState ("Second Step");
			ct.addMemento (orig.createMemento());
			orig.setState ("Third Step");
			ct.addMemento (orig.createMemento());
			//The fourth step was not stored in Caretaker
			orig.setState ("Fourth Step");
			//Change index value (below) to see what
			//happens when you retrieve a state
			orig.setMemento (ct.getMemento(0));
		}
	}
}

Working with the Memento

After the initial struggle of getting the Memento design pattern squared away, I came to see how easy it can be adapted to for use with a wide variety of applications. Notice in the example that in an abstraction of step-by-step process, the first three steps (states) were saved by a memento for retrieval and resetting the sequence. The length of the storage array is 3 instead of 4 simply because the last step was not saved. By placing between 0 and 2 in the getMemento method, you can retrieve any of the saved states. This would simulate the retrieval of a “saved place” in an application that allows a user to save previous places (states) in an online learning environment and later retrieve them.

8 Responses to “ActionScript 3.0 Memento Design Pattern: Encapsulating Saved States”


  1. 1 Timbot

    Another nicely done article.
    You might like this; http://code.google.com/p/as-hive/
    In this framework, states encapsulate sequences of instructions, and are handled by a state manager. The sequences are also stored in dictionaries as mementos when instantiated. It’s cool, there is a lot to see in there.
    -t.

  2. 2 Bill Sanders

    Hi Timbot,

    I looked at Hive. I’d think that a state/MVC combination would be very interesting.

    Bill

  3. 3 Dan Schultz

    You can also take the memento pattern one step further by using ByteArray’s and a database. If you persist the type of object where the memento came from, and the memento itself to a blob in a database, you could potentially re-instantiate the state of a whole application.

    I’ll be writing a post about this on my blog sometime soon, but as always Bill, another great write up!

    Dan

  4. 4 Bill Sanders

    Dan,

    Thanks for that insightful comment. Whoaaa! What you’re suggesting could set mementos from here to the moon and back if you wanted. That would be totally cool. When you get the write-up on your blog, send us a link to it.

    Take care,
    Bill

  5. 5 cubiclegrrl

    Mr. Sanders:

    I’m a Java programmer trying to OOP in Flash/Flex 3 these days. A couple of questions for the above example:

    1.) Is the “Memento” class stored in an .AS file or some other format?
    2.) What happens when you try incorporating a non-visual, Memento-like class into the script section of an MXML file?

    The overwhelming emphasis in the documentation (at Adobe and elsewhere) is on custom classes that merely extend the base ActionScript classes, not anything you’d to encapsulate information. Your work is the closest I’ve found for that, but information about bridging the visual and non-visual worlds is sorely lacking.

    Thanks much,

    cubiclegrrl

  6. 6 Bill

    Hi Cubiclegrrl,

    1. All of the components that make up the example Memento are in .as files. The main parts (following the names used in the Design diagram) are:
    a. Memento.as
    b. Originator.as
    c. Caretaker.as

    The DoLoadFMS.as is the equivalent to what most Java programmers would call the “Main” and the LoadSlide.as is just a utility class for loading the slides.

    2. The only component used (visual) was a button component and a black graphic backdrop was added. Both could have been handled in code, but slapping on the graphic was super easy and all of the components were called by the same code as with Flex (I believe). I’m pretty sure that the Flex button components can be access through an MXML file. (I’ve not spent enough time yet with Flex, but Chandima and others on this list have. However, the same basic AS 3.0 code works with both Flex and Flash up to a point.)

    Your point about bridging the visual and non-visual is something I haven’t really thought about until recently. For the most part, I’ve been trying to move from a combination of drawn-on-the-stage visual (in Flash) to all code so that both Flex and Flash users can more easily use the same files. On this blog, I’m going to be moving more toward Flex, but as a whole, we’re trying to make it available to both Flash and Flex users.

    Thanks for your feedback and please feel free to add more comments.
    Kindest regards,
    Bill

    (It’s not Mr. Sanders….makes me feel older than I am!)

  7. 7 cubiclegrrl

    Bill:

    I’ll take a closer look at the code, with that clarification in mind.

    Thanks so much!

    - cubiclegrrl

  8. 8 Paolo Carraro

    Hi, i’m reading AS3 Design Pattern and I’ve just implemented the Memento pattern in my actual app. I’d thank you for your work that help me everyday!

    Now the question about Memento and custom classes.
    I set my custom classes by [RemoteClass] metadata tag cause when I save the state I want force to pass this classes by Value and not by Reference.
    It’s the best practise?

    and then… if my custom classes extend Flex or Flash classes, this way doesn’t work cause i can’t modify the super classes.

    Thank you in advance
    Paolo

  1. 1 Saving Flex’s Application State to a Database

Leave a Reply