« An example of the Prototype Pattern | Inicio | [OT] The new member of the design-nation family »

An example of the Prototype Pattern ( the Java version )

Professor Coupling is a Spanish scientific that is planning to conquer the world. Do you want to read about the problems he encountered, and how he solved them using the prototype pattern?

Professor Coupling was a respected Spanish scientist, that became crazy because of the bad working conditions that all the Spanish scientists must suffer ( well, and because his girlfriend started to date another man ). So he became an evil genius, and now, he only thinks about conquering the world!!!.

professorCoupling.jpg
Professor Couplig

So, he has developed a cloning machine. A very special cloning machine, because it can be programmed in Java.

Professor Coupling’s plan is to clone as many sheeps (Any of various usually horned ruminant mammals of the genus Ovis in the family Bovidae ) as possible ( I don’t know exactly why, remember, he’s a genius, but he’s crazy ).

sheep.jpg
A sheep

So, the cloning machine looks like this:

class CloningMachine { public CloningMachine( ) { } public Sheep buildClone( ) { return new Sheep( ); } public Sheep[] buildManyClones( int cloneNum ) { Sheep[] returnArray = new Sheep[ cloneNum ]; for( int k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

And the sheep will be like:

class Sheep { public Sheep( ) { //this is a spanish sheep, so it sounds like a spanish sheep! System.out.println( "beeeee. I'm a new Sheep" ); } }

After flooding the world with sheeps ( it was his evil plan, not mine ), Professor Coupling noticed that cloning a few thousands of cows could help him to conquer the world faster. But his cloning machine was not built to clone cows, it was just built to clone sheeps.

cow.jpg
A cow

So, he decides to add the functionality needed to clone cows. How?. Look:

class CloningMachine { function CloningMachine( ) { } public Sheep buildClone( ) { return new Sheep( ); } public Cow buildCowClone( ) { return new Cow( ); } public Sheep[] buildManyClones( int cloneNum ) Sheep[] returnArray = new Sheep[ cloneNum ]; for( int k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

Professor Coupling is crazy, but he is not an idiot. He soon realizes that he’s going to be in trouble if he wants to clone other animals, like, for instance, birds, or even humans.

After thinking about the problem carefully, Professor Coupling gives it another try:

class CloningMachine { function CloningMachine( ) { } public Object buildClone( String type ) { if( type.equals( "sheep" ) ) { return new Sheep( ); } else if ( type.equals( "cow" ) ) { return new Cow( ); } } public Sheep[] buildManyClones( int cloneNum ) Sheep[] returnArray = new Sheep[ cloneNum ]; for( int k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

After a few minutes of hysterical laughs, Professor Coupling begins to think about how he has implemented his cloning machine, and he soon finds some weak points.

First, the buildClone method returns an Object, not a Sheep or a Cow. Why? Because this method doesn’t know what it’s going to create. Professor Coupling ( remember, he’s crazy, but he’s not an idiot ) feels that may not be the best way to solve the problem.

And he also notices that if he wants to clone another animal, he will have to change his cloning machine again. Hmm, that’s not easy to maintain.

But then, an idea begins to reach his brain. He doesn’t know exactly how, but what could happen if he could give the cloning machine an animal ( a sheep, a cow, a human, whatever animal ), and tell the machine: “give me 500 like this one”. Brilliant!. He will never have to worry about how the machine works, it will just give him as many copies of an animal he provides as needed.

Professor Coupling then remembers when he was a student, and read a book titled “Design patterns: Elements of reusable object-oriented software” ( the GoF ), and that thing called “The Prototype pattern”.

So, the cloning machine cannot know what to clone and how to clone it. That will be a responsibility of any animal. The cloning machine will just receive an animal, and will tell him to clone itself as many times as needed, and then will return the resulting clones.

In fact, Professor Couplig has noticed that the creation of new cows can be a little more complex that the creation of new sheeps, so he wants to rely on the java cloning mechanism to clone sheeps, and to make the mechanism to clone cows a bit more flexible

So, the first thing to do will be to create an interface ( that extends Cloneable, so it implements clone( ) ) that both the Sheep and the Cow will implement

public interface CloneableAnimal extends Cloneable { public CloneableAnimal duplicate( ); }

[ Note ].It will also be possible that all the different animals will extend a base class, so the return type of duplicate( ) will be that base class. But I will continue my example implementing an interface because I think it’s more flexible.

That method ( duplicate ) will be the one that will create and return a new copy of any single animal that implements it.

So, here’s a sheep:

public class Sheep implements CloneableAnimal { public Sheep( ) { System.out.println( "Sheep template created" ); } public CloneableAnimal duplicate( ) { System.out.println( "the Sheep will clone itself" ); Sheep returnValue = null; try { returnValue = ( Sheep ) super.clone( ); } catch( Exception e ) { System.out.println( "error cloning Sheep" ); } return returnValue; } public String toString( ) { return "I'm a sheep clone, beeeeee"; } }

As you can see, the duplicate( ) method calls the clone method of Sheep's superclass ( Object ) Here’s a cow:

public class Cow implements CloneableAnimal { public Cow( ) { System.out.println( "Cow template created" ); } public CloneableAnimal duplicate( ) { System.out.println( "creating a new Cow instance" ); return new Cow( ); } public String toString( ) { return "Muuuu, cow clone" ; } }

And Professor Coupling will want to do something like this:

public class ProfessorCoupling { public static void sayIt( String words ) { System.out.println( "" ); System.out.println( words ); System.out.println( "" ); } public static void main( String[] args ) { CloningMachine cMachine = new CloningMachine( ); sayIt( "creating Sheep and Cow templates" ); Sheep sheepTemplate = new Sheep( ); Cow cowTemplate = new Cow( ); Cow clonedCow = ( Cow ) cMachine.newClone( cowTemplate ); sayIt( "first cloned cow" ); Sheep clonedSheep = ( Sheep ) cMachine.newClone( sheepTemplate ); sayIt( "first cloned sheep" ); System.out.println( clonedSheep ); sayIt( "Creating 10 new cows" ); CloneableAnimal[] newCows = cMachine.cloneMany( 10, cowTemplate ); sayIt( "Creating 10 new Sheeps" ); CloneableAnimal[] newSheeps = cMachine.cloneMany( 10, sheepTemplate ); sayIt( "Testing the cows created" ); for( int i=0; i< newCows.length; i++ ) { System.out.println( newCows[ i ] ); } sayIt( "Testing the sheeps created" ); for( int i=0; i< newSheeps.length; i++ ) { System.out.println( newSheeps[ i ] ); } } }

So, finally, the cloning machine will be able to receive an animal ( an instance of a class ), and tell it to create as many copies of itself as needed:

public class CloningMachine { public CloningMachine( ) { } public CloneableAnimal newClone( CloneableAnimal template ) { return template.duplicate( ); } public CloneableAnimal[] cloneMany( int itemCount, CloneableAnimal template ) { CloneableAnimal[] returnValue = new CloneableAnimal[ itemCount ]; for( int i=0; i< itemCount; i++ ) { returnValue[ i ] = template.duplicate( ); } return returnValue; } }

So, Professor Coupling can keep on flooding the world with the clones created by his machine, knowing that he is able to create copies of any thing he wants, because he has given his cloning machine the ability to generate objects whose type is unknown.

After some further reading, Professor Coupling also realizes that he has separated the code that handles the details of creating the new animals from the code that actually creates them ( that means, that, for example, if he wants to create 1000 red sheeps today, and 1000 blue sheeps tomorrow, he only has to put a painting machine next to the cloning machine, and that machine will handle the way that those sheeps are painted, without knowing how they were created ).

Thanks to Celia Carracedo for the drawings of the sheep, the cow, and evil Professor Coupling.

Comentarios

Wonderful article. Nicely explained.

Regards,
Ritu.

Cool. It is one of the most colorfull explanations I'd ever read.

I don't think I understand...why create this prototype when Java already has the Cloneable interface, and you can just call the clone() method on an object that extends it?

Well, maybe sometimes just calling the clone( ) method can be enough, but some otrher times it might be not.

Think, for instance, that you don't want a to create an exact copy of the original object, but just want to duplicate it's structure so the object can be materialized after being deserialized ( sorry, my english is horrible, I hope that makes sense ). The reason to implement a prototype is that it's ( or it can be ) more flexible that just cloning an object.