« Un ejemplo del PatrÛn Prototype | Inicio | Planeta cÛdigo »

Un ejemplo del PatrÛn Prototype ( la versiÛn Java )

El Profesor Dispar es un cientÌfico espaÒol que est· planeando dominar el mundo. øQuieres conocer los problemas con los que se ha encontrado, y cÛmo los ha resuelto implementando el patrÛn prototype?

El Profesor Dispar era un respetado cientÌfico espaÒol, que se convirtiÛ en un genio del mal por sus malas condiciones laborales ( y por que su novia se la pegaba con otro, la verdad ). Ahora, su ˙nico deseo es llevar a cabo su malvado plan para °°°dominar el mundo!!!

professorCoupling.jpg
El Profesor Dispar

AsÌ que, en sus delirios paranoides, ha construido una m·quina para clonar. Una m·quina para clonar muy especial, porque puede ser programada en Java

El plan del Profesor Dispar es clonar todas las ovejas que pueda, para asÌ controlar la economÌa mundial y dominar el mundo ( la verdad, no entiendo el porquÈ de ese plan, pero recuerda, aunque estÈ loco, es un genio! ).

sheep.jpg
Una oveja ( vista frontal )

La m·quina para clonar es algo asÌ:

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; } }

Y la oveja:

class Sheep { public Sheep( ) { System.out.println( "beeeee. Soy una oveja reciÈn creada" ); } }

Tras inundar el mundo con ovejas clonadas ( es su malvado plan, no el mÌo ), el Profesor Dispar se dio cuenta que clonar unos cuantos miles de vacas le ayudarÌa a dominar el mundo m·s r·pido. Pero su m·quina para clonar no fue construida para clonar vacas, sino para clonar ovejas

cow.jpg
Una vaca ( vista lateral )

AsÌ que el malvado genio del mal decide aÒadir a su m·quina la funcionalidad necesaria para clonar vacas. øCÛmo?. Mira:

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; } }

El Profesor Dispar est· loco, pero no es idiota. Por tanto, enseguida se da cuenta de que puede encontrarse con problemas si quiere clonar otros animales, como, por ejemplo, p·jaros, o incluso humanos

Tras pensar cuidadosamente sobre su problema, hace otro intento:

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; } }

Tras varios minutos de las tÌpicas risas histÈricas, el Profesor Dispar empieza a pensar en la forma en que ha implementado su m·quina para clonar, y enseguida encuentra varios puntos dÈbiles.

En primer lugar, el mÈtodo buildClone devuelve un Object, no una oveja ( Sheep ) o una vaca ( Cow ). øPor quÈ?. Porque este mÈtodo no sabe lo que va a crear a priori. El Profesor Dispar ( recuerda, est· loco, pero no es idiota ) barrunta que Èsta no es la mejor soluciÛn posible

TambiÈn se da cuenta que si en alg˙n momento quisiera clonar alg˙n otro animal, deberÌa cambiar de nuevo su m·quina para clonar. Y eso no hace su m·quina f·cil de mantener.

Pero entonces, una idea empieza a abrirse paso en su malvado cerebro. A˙n no sabe exactamente cÛmo hacerlo, pero øquÈ pasarÌa si pudiera darle algo a la m·quina( una oveja, una cabra, un humano, o una piedra ) y pedirle a la misma que le devolviera 500 copias del mismo?. °°Brillante!! ( m·s risas histÈricas ). AsÌ, no tendrÌa que preocuparse de cÛmo funciona la m·quina, simplemente la m·quina le devolverÌa tantas copias como necesitara del original que Èl le facilitara.

Entonces, el Profesor Dispar recuerda sus tiempos de estudiante, cuando leyÛ un libro llamado "Patrones de diseÒo: Elementos de software orientado a objetos reutilizable" ( el GoF ), y aquella cosa que se llamaba el "patrÛn prototype"

Por tanto, la m·quina para clonar no puede saber quÈ tiene que clonar ni cÛmo debe clonarlo. …sa ( la creaciÛn de la copia ), ser· una responsabilidad de cada uno de los animales ( o cosas a clonar ). La m·quina de clonar, simplemente recibir· un animal, y le dir· a Èste que produzca tantas copias de sÌ mismo como se necesiten, y luego se las devolver· al Profesor Dispar.

De hecho, el Profesor Dispar se ha dado cuenta de que la forma en la que deben crearse las nuevas copias de los animales no ha de ser la misma para todos, sino que en algunos casos le va a interesar utilizar el mecanismo de clonado de Java, y en otros tener un control m·s fino del mismo.

AsÌ que, la primera tarea del Profesor ser· crear un interfaz ( que extiende Cloneable, implementando de este modo el mÈtodo clone( ) ), que ser· el que implementen tanto la Vaca como la Oveja

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

[ Nota ]. SerÌa posible que todos los animales extendieran de una clase base, y que por tanto el tipo que devuelve el mÈtodo duplicate( ) fuera esa clase base. Pero yo voy a continuar mi ejemplo con este interfaz, porque de esta forma el diseÒo es mucho m·s flexible.

Ese mÈtodo duplicate( ) ser· el encargado de crear y devolver una nueva copia de cada animal que lo implemente.

La oveja ahora ser·:

public class Sheep implements CloneableAnimal { public Sheep( ) { System.out.println( "Creada la plantilla de la oveja" ); } public CloneableAnimal duplicate( ) { System.out.println( "La oveja se va a clonar a sÌ misma" ); Sheep returnValue = null; try { returnValue = ( Sheep ) super.clone( ); } catch( Exception e ) { System.out.println( "error cloning Sheep" ); } return returnValue; } public String toString( ) { return "Soy una oveja clonada, beeeeee"; } }

Como se puede ver, el mÈtodo duplicate( ) de la oveja ejecuta el mÈtodo clone( ) de su superclase.

AquÌ est· la vaca:

public class Cow implements CloneableAnimal { public Cow( ) { System.out.println( "Creada la plantilla de la vaca" ); } public CloneableAnimal duplicate( ) { System.out.println( "creando una nueva instancia de Cow" ); return new Cow( ); } public String toString( ) { return "Muuuu, soy un clon de vaca" ; } }

Ahora, el Profesor Dispar tan sÛlo tendr· que hacer algo asÌ:

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( "primera vaca clonada" ); Sheep clonedSheep = ( Sheep ) cMachine.newClone( sheepTemplate ); sayIt( "first cloned sheep" ); System.out.println( clonedSheep ); sayIt( "Creando 10 vacas nuevas" ); CloneableAnimal[] newCows = cMachine.cloneMany( 10, cowTemplate ); sayIt( "Creando 10 ovejas nuevas" ); CloneableAnimal[] newSheeps = cMachine.cloneMany( 10, sheepTemplate ); sayIt( "Probando las vacas" ); for( int i=0; i< newCows.length; i++ ) { System.out.println( newCows[ i ] ); } sayIt( "Probando las ovejas" ); for( int i=0; i< newSheeps.length; i++ ) { System.out.println( newSheeps[ i ] ); } } }

Ahora, el Profesor Dispar puede seguir inundando el mundo con los clones creados por su m·quina ( m·s risas histÈricas ), sabiendo que puede crear copias de todo lo que le dÈ la gana, porque le ha dado a su m·quina el "don" de crear objetos sin saber de quÈ tipo deben ser.

Pero el Profesor es un hombre de ciencia, y en su af·n por alcanzar el conocimiento absoluto, sigue leyendo documentaciÛn sobre el patrÛn prototype, y entonces se da cuenta de que tambiÈn ha separado el cÛdigo que crea los objetos del cÛdigo que maneja los detalles de la creaciÛn de nuevos objetos ( eso queire decir que, por ejemplo, si quiere crear 1000 ovejas rojas hoy, y 1000 ovejas azules maÒana, tan sÛlo debe aÒadir una m·quina para pintar animales al lado de la m·quina para clonar, y esa m·quina de pintar se encargar· de darlas color, sin saber cÛmo ni donde se han creado esos animales ).

Gracias a Celia Carracedo, hoy concretamente por los dibujos de la oveja, la vaca, y el malvado Profesor Dispar.

TrackBack

URL del Trackback para esta entrada:
http://ctarda.dreamhosters.com/cgi-bin/mt-tb.cgi/676

Comentarios

Cuando en la clase ProfessorCoupling haces:
CloningMachine cMachine = new CloningMachine( );

no indicas a que clase de las 2 que has llamado CloningMachine, aunque me parece q te refieres a una tercera de la cual no has puesto el cÛdigo

Efectivamente.

Tremenda cagada. La clase CloningMachine correcta es:

public class CloningMachine
{
public CloningMachine( )
{

}

public Clonable createCopy( IClonable template )
{
return template.getCopy( );
}

public Clonable[] createManyCopies( int numCopies, IClonable template )
{
Clonable[] returnArray = new Clonable[ numCopies ];
for( int i=0; i< numCopies; i++ )
{
returnArray[ i ] = template.getCopy( );
}

return returnArray;
}
}


Gracias por darte cuenta del error!

Un ejemplo cojonuti!!!
muy bueno de verdad, divertido y eficaz.