Bill Sanders has a great post on the Memento design pattern over at his blog. After reading it, I thought I’d chime in and post a technique that takes the memento one step further. This approach allows you to serialize a Memento object into a ByteArray and save it into a database. Then, retrieving the Memento object from the server, dynamically instantiated it, and restoring its previous state.
One major draw back to the Memento, as you’ll see, is that restoring an object’s state can be a very expensive operation. Especially in a Flex environment where restoring a Memento could trigger a large display list invalidation. For that reason, the Memento is not always the ideal pattern for implementing undo/redo functionality. The alternative pattern for implementing this functionality is the Command pattern. With the Command pattern, each command is only concerned about a particular action to get to the current state of the application. With this, you can have an undo() method in each of your commands that undoes whatever action was performed in your execute() method.
Ok, so where could we apply the Memento then? Hmm .. how about a Monopoly game! Since a game of Monopoly can be pretty lengthy, the user might want to be able to save the game on the server, so that he/she can come back later to finish it off. There’s a couple ways to accomplish this functionality:
- Create a multitude of database tables that represent objects in your application. For example, a Player’s table to keep track of the current players, how much money they have, etc. A Properties table to keep track of the game’s properties. A Properties to Players linking table to store which properties each player owns, and so on.
- OR, create one table whose role is to store Mementos for each of the objects in the game. I think this approach sounds easier, and since it’s in the scope of this article, we’re going to focus on this approach.
The Memento Classes

In order for our application to save its state using the Memento pattern, we need to write a couple classes and interfaces that our objects will implement. Note that my Memento classes slightly differ from that described on Wikipedia and Bill Sanders blog. The reason for this was that I wanted to inspect which type of object each Memento originated from. By doing this, you can re-instantiate the Memento dynamically when it comes back from the database. I also wanted any classes that supported restoration to be of a certain type – IRestorable.
Each class that you want to save and restore state to must implement the IRestorable interface. This interface has two simple methods that either creates or accepts a Memento object.
1 2 3 4 5 | public interface IRestorable { function restore(state:ObjectState):void; function save():ObjectState; } |
Next is the Memento class that is called ObjectState. This class is where you store all the data that the class needs to restore its state back to what it was. These objects can also be serialized and saved to the database (more on this later). You’ll notice that I’ve marked this class as dynamic so that you can add anything you want to it. The only defined property it has is className. You set this to the fully qualified class name that generated the Memento. Another important thing to note: you must put the [RemoteClass] metatag in the ObjectState class definition. I’ll show you later how you can use this property to re-instantiate the object based on this class name property.
1 2 3 4 5 | [RemoteClass(alias="my.custom.package.ObjectState")] public dynamic class ObjectState { public var className:String; } |
Pretty simple stuff, huh? Let’s take a look at a simple class that implements both of these classes. This class, called MyCustomComp, implements the IRestorable interface with the two methods described above. The save() method’s job is to take all the data that this component needs to re-instantiate itself and save it to a new ObjectState. In our case, it’s the text strings from the three TextInput controls. The restore() method’s job is to take those three text strings, and reapply them to our TextInput controls. So whatever is done in the restore() method, needs to be saved to the ObjectState in the save() method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | public class MyCustomComp extends UIComponent implements IRestorable { // Sub-components in our component that we want to // restore the data to. public var textInput1:TextInput; public var textInput2:TextInput; public var textInput3:TextInput; public function MyCustomComp() { super(); } override protected function createChildren():void { super.createChildren(); // Create the sub-components. textInput1 = new TextInput(); textInput1.text = "Text 1"; addChild(textInput1); textInput2 = new TextInput(); textInput2.text = "Text 2"; addChild(textInput2); textInput3 = new TextInput(); textInput3.text = "Text 3"; addChild(textInput3); } public function restore(state:ObjectState):void { // Make sure to throw a TypeError if the class name is // incorrect. if (state.className != flash.utils.getQualifiedClassName(this)) throw new TypeError("This ObjectState was not created from the MyCustomComp class"); // Take the text data from the ObjectState and restore // it to our sub-components. textInput1.text = state.text1; textInput2.text = state.text2; textInput3.text = state.text3; // Restore the position of the component. x = state.xPos; y = state.yPos; } public function save():ObjectState { var state:ObjectState = new ObjectState(); state.className = flash.utils.getQualifiedClassName(this); // Since the ObjectState is dynamic, we can set anything // on it. Set the text from each of the sub-components // into our memento object. state.text1 = textInput1.text; state.text2 = textInput2.text; state.text3 = textInput3.text; // Save the X and Y positioning of this component. state.xPos = x; state.yPos = y; return state; } } |
Serializing the ObjectState to the Database
When it’s time to send the ObjectState across the wire and save it to the database, we need to do a simple operation first. This operation will save the ObjectState into a ByteArray so that the database can store it.
1 2 3 4 5 6 7 8 9 10 11 12 13 | // The component that we want to save and restore data to. var myRestorableComp:MyCustomComp = new MyCustomComp(); // Save the component's state. var state:ObjectState = myRestorableComp.save(); // Write the state object into a ByteArray. var stateBytes:ByteArray = new ByteArray(); bytes.writeObject(state); // Code to send the ByteArray to the server via Flash Remoting. myService:RemoteObject = myRemotingService; myService.saveMemento(stateBytes); |
Also, in order to save serialized objects to a database, you need to set the field in which they’re stored as a BLOB. This way, the serialized structure of the object isn’t modified when you save it.
Retrieving the Memento from the Server
After we save the state to the database, a user will more than likely want to retrieve it. Also, you might want to dynamically re-instantiate the component that the Memento’s originated from. You can achieve this by passing the ObjectState’s className property into Flash’s flash.utils.getDefinitionByName() method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public class MyCompContainer extends Canvas { private var service:RemoteObject; public function MyCompContainer() { super(); service = new RemoteObject(); service.addEventListener(ResultEvent.RESULT, retrievedMementoHandler); ... service.retrieveMemento(someUniqueMementoId); } // The result handler that was added to the remoting object. private function retrievedMementoHandler(event:ResultEvent):void { // We saved the ObjectState into a ByteArray, so we're // going to get it back as a ByteArray. var stateBytes:ByteArray = event.result as ByteArray; stateBytes.position = 0; // Read the Memento from the ByteArray. var compState:ObjectState = stateBytes.readObject() as ObjectState; // We can inspect the type that the ObjectState // originated from. var restorableComp:IRestorable = flash.utils.getDefinitionByName(compState.className); restorableComp.restore(compState); // If this is a UIComponent, let's add it to the stage. // Since we saved the x and y positioning in the // ObjectState, it will position itself to where it was // when it was saved. if (restorableComp is UIComponent) addChild(restorableComp as UIComponent); } } |
By using the Memento pattern, we’ve encapsulate the implementation of storing and retrieving an object’s state. We’ve also made it generic enough, that we can serialize the object’s state and store it into a database table. Once in the database table, the state can be retrieved and instantiated later.
Pitfalls of this Approach
Like any design pattern out there, this approach has its draw backs. One consequence of this technique is the difficulty to change the data inside your Mementos. The reason for this is the way that we use serialization. Since the objects are serialized in the database, you can’t easily add additional data to the ObjectStates. However, there are workarounds for this. You can save a version number along with your ObjectState. This version number can be used in conjunction with a separate class that deals with reading each ObjectState’s data. When the class inspects the version number, it can change its parsing logic to deal with different versions of the ObjectState.
Another drawback is the inability to do a database query on the data inside your ObjectStates. Again, since the objects are serialized, there’s no easy way to do this. You can, however, work around this though by storing the query data in either a separate table, or along side the ObjectState when it’s saved.
Hopefully this technique is something you can add to your toolkit. It definitely has its share of drawbacks, but if you’re looking for an easy way to save the state of your application, this is certainly a pretty trivial and elegant way of accomplishing it.


Recent Comments