An example of the memento pattern ( the java 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.
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.
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.
package sheep;
public class SheepMemento
{
private int serialNumber;
private String location;
public SheepMemento( int serial, String loc )
{
serialNumber = serial;
location = loc;
}
public setLocation( String newLocation )
{
location = newLocation;
}
public String getLocation( )
{
return location;
}
}
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.
package sheep;
public class SheepMemento
{
private int serialNumber;
private String location;
public SheepMemento( int serial, String loc )
{
serialNumber = serial;
location = loc;
}
}
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.
So, the sheep package will contain the two following classes ( first of all the Sheep class ):
package sheep;
public class Sheep
{
private int serialNumber;
private String location;
public Sheep( int serial, String loc )
{
serialNumber = serial;
location = loc;
}
public SheepMemento getMemento( )
{
return new SheepMemento( serialNumber, location );
}
public void setMemento( SheepMemento memento )
{
serialNumber = memento.serialNumber;
location = memento.location;
}
public void setLocation( String newLoc )
{
location = newLoc;
}
public String getLocation( )
{
return location;
}
public String toString( )
{
return "Sheep: serialNumber " + serialNumber + " location " + location;
}
}
The SheepMemento class will be:
package sheep;
public class SheepMemento
{
protected int serialNumber;
protected String location;
protected SheepMemento( int serial, String loc )
{
serialNumber = serial;
location = loc;
}
}
And finally, the Sergeant:
package sergeant;
import sheep.Sheep;
import sheep.SheepMemento;
public class Sergeant
{
public void attack( )
{
Sheep mySheep = new Sheep( 1, "here" );
SheepMemento initState = mySheep.getMemento( );
System.out.println( "initial position" );
System.out.println( mySheep );
System.out.println( "change its position" );
mySheep.setLocation( "there" );
System.out.println( "final position" );
System.out.println( mySheep );
System.out.println( "retreat!" );
mySheep.setMemento( initState );
System.out.println( mySheep );
}
public static void main( String[] args )
{
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.
Comentarios
Nice Example to understand the basics .
What i felt is that to go to more depth like ,
if we require more that one state ,
we will need an undoList collection / some sort of stack to keep these momentos and return them as needed
So it helps in making a more concrete and practical example .
Thanks Sir
Praveen Kumar(prakumar@quark.com)
Publicado por: Praveen Kumar | November 9, 2005 12:26 PM