« [Cocoa] About the NSSlider control | Inicio | An example of the memento pattern ( the java version ) »

An example of the memento pattern ( the actionscript version )

Conquering the world is not easy. You and me both know it. And Professor Coupling knows it too.

He has the knowdlege, he has a plan, he has the skills, and he has even the looks, but there are a lot of little details to care for before he can finally conquer the world!!.

In previous posts, be have seen how he has implemented the prototype pattern ( to create his army of clones –hey, I’ve just noticed the joke- ), the extension objects pattern ( to assign their roles ), the command pattern ( to assign them their orders ) and the observer pattern ( to implement a communications system ). It seems that Professor Coupling has had a lot of work, but was it enough?. NO!! ( muhahahahahahaha ).

If you remember the post about the observer pattern ( and I doubt you can remember it, because I don’t ), we left our cows and sheeps in the instant previous to the final attack to conquer the world ( while Professor Coupling laughed histerically ). ( insert heroic music in the background ) They are waiting to receive the order to attack. Each cow and each sheep is on alert, listening to the radio, waiting to hear the secret signal, and to abandon their position and follow the orders they received.

Professor Coupling is just going to press the "attack" button, when suddenly he notices something ( and suddenly the heroic music stops ). “What if I have to send the “retreat” order to all my troops?. It’s not that my plan is going to fail ( I’m an evil genius after all ), but you know, you can’t count on your subordinates, so what would happen if I had to cancel the attack when my army has started its advance ( glorious advance, of course )?”.

Definitively, he is a genius. He has noticed a very subtle “bug” in his plan. What happens if he has to order his troops to cancel the attack once they have left their original positions?. Well, he has implemented a communications system, so he can send the retreat-secret-singal to all his soldiers, can’t he?. ( muhahahahahahhaha, you know ). But, cows and sheeps are well know for their lack of memory. They are also known for the quality of the cheese that can be made with their milk, but that is out of the scope of this tutorial.

The point is: a cow has no memory. A sheep has no memory. Period. They can just remember one thing. So they can remember that they have to attack, or to move somewhere, but as soon as they put that information into their brain, they are not able to remember anything else ( like, for instance, where they were five minutes before, or if they borrowed something from someone else ).

So, Professor Coupling can tell them to go back to their initial position, but that’s completely useless, before they can not remember where their initial position was.

memento1.jpg

But ( switch the heroic music on again, please ), Professor Coupling vaguely remembers when he was a young student, and he also vaguely remembers when he read about the memento pattern.

What if every sheep and every cow write down on a notebook their initial position ( the only thing they remember ), and give that notebook to their Sergeant?. What if the sergeant takes care of those notebooks, and give them back to their owners if they have ( the owners ) to go back to their initial position?. Problem solved!! ( muhahahahahahha ). That’s perfect!!. The sheeps and cows will only have to remember one position ( the position where they are supposed to go, no matter if they are attacking or retreating ), while an external entity will take care of that information.

memento2.jpg

How could a sheep store that information on a notebook?. Easy. Every sheep will be able to create an instance of a class to store that information.

import sheep.Sheep class sheep.SheepMemento { private var serialNumber: Number; private var location: String; private var creator: Sheep; function SheepMemento( serialNumber: Number, location: String ) { this.serialNumber = id; this.location = location; } public function setLocation( newLocation: String ) { this.location = newLocation; } public function getState( creatorRef: Sheep ) { return { serialNumber: this.serialNumber, location: this.location }; }

And the Sheep class

import sheep.SheepMemento class sheep.Sheep { var serialNumber: Number; var location: String; function Sheep( serial: Number, loc: String ) { this.serialNumber = serial; this.location = loc; } public function getMemento( ): SheepMemento { return new SheepMemento( this.serialNumber, this.location ); } public function setMemento( state: SheepMemento ) { var stateData: Object = state.getState( ); this.serialNumber = stateData.serialNumber; this.location = stateData.location; } //Public setters. Change inner state public function setLocation( newLocation: String ) { this.location = newLocation; } //For debugging purposes public function toString( ): String { return "Sheep id: " + this.serialNumber + " @ " + this.location; } }

And finally, the Sergeant:

import sheep.Sheep import sheep.SheepMemento class sergeant.Sergeant { function Sergeant( ) { trace( "grrrrr, I'm the Sergeant" ); } public function attack( ) { var sheep: Sheep = new Sheep( 1, "here!" ); trace( sheep ); var sheepMemento: SheepMemento = sheep.getMemento( ); sheep.setLocation( "theeeeeere" ); trace( sheep ); sheep.setMemento( sheepMemento ); trace( sheep ); } public static function start( ) { var sergeant: Sergeant = new Sergeant( ); sergeant.attack( ); } }

But wait!!!. Professor Coupling has noticed that there is a potential flaw in his plan. If the Sergeant takes care of all the initial positions of all the sheeps, there is a big security risk, because what happens if that information is stolen by the pesky enemy?. Well, the pesky enemy will have access to a lot of information about the Professor’s plan. Or even worst!!!. The pesky enemy could change that information!!!!. But wait, again!!. If the information that the Sergeant stores is encrypted, or is only accessible to the sheeps, the problem is solved, nobody could change that information!.

So, to avoid the changes in that information, Professor Coupling will do two different things. First of all, the fields in the SheepMemento class could only be set through the constructor. That’s the way to ensure that those values can only be set when the class is created, and no later.

But unfortunately, that’s not enough ( it’s so difficult to have a really good plan ). Professor Coupling wants to avoid that the information stored in the memento could be changed by anybody. In fact, he wants that only a sheep could create its memento, and could set its data. So, he can be sure that nobody could interfere or obscure the information stored in the memento.

Doing that in Java is easy. Professor Coupling simply puts the memento class in the same package than the sheep, and makes its constructor and its fields protected. That way, only the sheeps could create mementos and assign their values.

But doing that in actionscript is not that easy. There is no "protected" keyword ( neither functionality ) in actionscript ( the heroic music stops again ).

Professor Coupling is a flash developer and has been a flash developer for years, so he is well know for his ability to find workarounds. So, he soon finds a possible solution ( please, heroic music again ). But how??. He thinks: "if the sheep passes a reference to itself when it creates the memento, it could check that reference before recovering its old style from the memento" ( muhhhhhhhaaaaaaaaaaaaahahahahaha ). He tries to explain to the sheep, but you know, some times if you want something to work you have to do it by yourself…

So, he changes the way that the sheep creates the memento, and the way that the sheep retrieves the information stored in the memento ( and that’s the most important part ). Before returning a value, the SheepMemento class, checks if that information corresponds to the entity that is asking for it. If it corresponds, it returns those values. If it doesn’t, it says "beeeeeeeeeee".

So, the final code will be ( first of all, the SheepMemento class ):

import sheep.Sheep class sheep.SheepMemento { private var serialNumber: Number; private var location: String; private var creator: Sheep; function SheepMemento( serialNumber: Number, location: String, creator: Sheep ) { this.serialNumber = id; this.location = location; this.creator = creator; } public function getState( creatorRef: Sheep ) { var returnValue: Object = null; if( this.creator == creatorRef ) { returnValue = { serialNumber: this.serialNumber, location: this.location }; } return returnValue; } }

The Sheep class will be:

import sheep.SheepMemento class sheep.Sheep { var serialNumber: Number; var location: String; function Sheep( serial: Number, loc: String ) { this.serialNumber = serial; this.location = loc; } public function getMemento( ): SheepMemento { return new SheepMemento( this.serialNumber, this.location, this ); } public function setMemento( state: SheepMemento ) { var stateData: Object = state.getState( this ); if( stateData != null ) { this.serialNumber = stateData.serialNumber; this.location = stateData.location; } else { trace( "memento not valid" ); } } //Public setters. Change inner state public function setLocation( newLocation: String ) { this.location = newLocation; } //For debugging purposes public function toString( ): String { return "Sheep id: " + this.serialNumber + " @ " + this.location; } }

And finally, the Sergeant:

import sheep.Sheep import sheep.SheepMemento class sergeant.Sergeant { function Sergeant( ) { trace( "grrrrr, I'm the Sergeant" ); } public function attack( ) { var sheep: Sheep = new Sheep( 1, "here!" ); trace( sheep ); var sheepMemento: SheepMemento = sheep.getMemento( ); sheep.setLocation( "theeeeeere" ); trace( sheep ); sheep.setMemento( sheepMemento ); trace( sheep ); } public static function start( ) { var sergeant: Sergeant = new Sergeant( ); sergeant.attack( ); } }

Muhahahahahahahahaha. Professor Coupling has done it again!!. He has been able to encapsulate the internal state of an object, put it in another object, and encapsulate it so well that it can only be retrieved by the object that created that package.

Just one more thing. What do you think about the way that Professor Coupling ( not me ) has implemented the sheep’s identity test?. Do you like that solution?.

I can think of another solution. Instead of storing in the memento a reference to its creator, it could store only the creator’s id, or a hashcode, or something similar. What do you think?

Comentarios

Why jump through those hoops to protect the data of the SheepMemento? If I really want to hack it, I can easily just do memento.getState(memento.creator) ...

I don't understand the purpose of checking the creator.

The justification of the pattern is to encapsulate the internal state of an object in a way that encapsulation can only be used by the object that creates it itself.

Form the GoF: "The Memento design pattern externalizes and records the internal state of an object so that it is possible to restore the object to its state later. The state of an object is recorded at strategic points so that undo mechanisms can allow users to restore an object to what it was before an operation. Memento describes a method of externalizing an object’s state without violating encapsulation".

That's not easy to achieve in actionscript, because there are not protected methods, and as I've said, the solution I've showed probably is not the best possible ( but it works, the "creator property is private" ). But the important concept is that we must try to encapsulate that internal state. That's why I check the creator. So, I can be sure that only the object that creates the memento uses it to restore its old state.