« [XP] Propiedad colectiva del código, tests, y coding standards | Inicio | Un ejemplo del Patrón Prototype ( la versión Java ) »

Un ejemplo del Patrón Prototype

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 ActionScript

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 { function CloningMachine( ) { } public function buildClone( ): Sheep { return new Sheep( ); } public function buildManyClones( cloneNum: Number ) { var returnArray: Array = new Array( ); for( var k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

Y la oveja:

class Sheep { function Sheep( ) { trace( "beeeee. Soy una nueva 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 function buildClone( ): Sheep { return new Sheep( ); } public function buildCowClone( ): Cow { return new Cow( ); } public function buildManyClones( cloneNum: Number ) { var returnArray: Array = new Array( ); for( var 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 function buildClone( type: String ): Object { if( type == "sheep" ) { return new Sheep( ); } else if ( type == "cow" ) { return new Cow( ); } } public function buildManyClones( cloneNum: Number ) { var returnArray: Array = new Array( ); for( var 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.

Por tanto ( recuerda, no hay clases abstractas en ActionScript ), todos los animales deberán implementar un interfaz, que contiene sólo un método:

interface ICloneable { public function clone( ): ICloneable; }

[ Nota ]. Sería posible que todos los animales extendieran de una clase base, y que por tanto el tipo que devuelve el método clone( ) 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 clone( ) será el encargado de crear y devolver una nueva copia de cada animal que lo implemente.

La oveja ahora será:

class Sheep implements ICloneable { function Sheep( ) { trace( "Hola, soy Dolly, me van a clonar en un plis" ); } public function clone( ): ICloneable { trace( "Beeee, soy un nuevo clon de Dolly" ); return new Sheep( ); } public function toString( ): String { return "{ Hola, soy una oveja clonada. }"; } }

Y aquí está la vaca:

class Cow implements ICloneable { function Cow( initFlag: Boolean ) { trace( "Muuuu, soy una vaca, a mí también me van a clonar en un momento" ); if( initFlag == true ) { init( ); } } private function init( ) { trace( "Soy una vaca inicializada, signifique eso lo que signifique" ); } public function clone( ): ICloneable { return new Cow( true ); } public function toString( ): String { return "{ sí, soy una vaca clonada, muuuuuu }"; } }

Ahora, el Profesor Dispar tan sólo tendrá que hacer algo así:

var cMachine: CloningMachine = new CloningMachine( ); cMachine.buildClone( new Sheep( ) ); cMachine.buildClone( new Cow( ) ); trace( "--" ); var sheepClones: Array = cMachine.buildManyClones( 5, new Sheep( ) ); var cowClones: Array = cMachine.buildManyClones( 5, new Cow( ) ); trace( "--" ); trace( "sheepClones " + sheepClones ); trace( "cowClones " + cowClones );

Por tanto, la máquina para clonar podrá recibir cualquier animal ( una instancia de una clase ), y mandarla que cree todas las copias de sí misma que se necesiten.

class CloningMachine { function CloningMachine( ) { } public function buildClone( template: ICloneable ): ICloneable { return template.clone( ); } public function buildManyClones( clonesNum: Number, template: ICloneable ): Array { var returnArray: Array = new Array( ); for( var k=0; k< clonesNum; k++ ) { returnArray[ k ] = template.clone( ); } return returnArray; } }

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 cread esos animales ).

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

Comentarios

xDDDD

una forma de explicar muy amena ;)

Pues sí que está bien explicado. Bueno me he enterado de poco, pero sin el ejemplo del profe me no hubiese podido cogerlo por ningún lado.

Excelente!
Muy original la forma de explicarlo :)
Como siempre, nunca faltan los animalitos a la hora de explicar la teoría de objetos

exelente =)

Excelente! quedamos a la espera de los demás patrones!

Extraordinario, muchas gracias.

Extraordinario. Muchas gracias.

Excelente ilustración del patrón. Muchas gracias porque fue de mucha ayuda.