« Julio 2005 | Inicio | Septiembre 2005 »

Agosto 31, 2005

Blogday 2005

Pues no pensaba, la verdad, pero nobleza obliga ( sobre todo si eres castellano ), asÌ que aquÌ van cinco blogs que me voy a atrever a recomendar. En este caso, al contrario que en intrascendencias, todos tratan de cosas muy "sesudas".

Vaya por delante que la tarea no es f·cil. Hay mucho ( en mi caso, mi feeddemon / netnewswire contiene unos 350 feeds ), y muy bueno, por lo que escoger sÛlo cinco implica dejar fuera a muchos.

En orden alfabÈtico:

Call me fishmeal. Ahora que estoy tan metido en Objective-C y Cocoa, un recurso imprescindible.

Creating Passionate Users. El blog de Kathy Sierra, uno de los autores de la serie de libros "Head First".

Luis de la Rosa. Aunque est· un poco orientado a la programaciÛn java en entorno Mac ( sobre todo con Eclipse ), toca de todos los palos: Java, Ruby, Cocoa,...

The server side. No sÈ muy bien si se puede calificar como blog o en realidad es algo m·s, pero aquÌ queda.

VersiÛn Cero. InformaciÛn muy variada sobre el mundo del desarrollo de software. Herramientas, libros, artÌculos, ...

Quedan muchos fuera, pero elegir sÛlo cinco es tan difÌcil...

Agosto 24, 2005

[J2ME] Tutorial sobre uso de luces en programaciÛn 3D

En el Developer World de Sony Ericcson han publicado la segunda parte de una serie de artÌculos sobre programaciÛn en 3D usando M3G.

El artÌculo, firmado por Mikael Baros, est· centrado en el uso de luces. Aunque el cÛdigo que lo acompaÒa est· escrito en Java, los conceptos de los que habla son portables a otros lenguajes y / o sistemas.

Una lectura interesante. El link

Agosto 20, 2005

[J2ME] Desarrollo de MIDlets en Mac OSX

Dudo mucho de la utilidad real de este "invento" a la hora de desarrollar un MIDlet en Mac OSX. Por un lado, la instalación de las herramientas necesarias no es especialmente sencilla ( aunque tampoco hay que ser un gurú del Unix ), por otro el desarrollo en sí no recibe mucha ayuda ( ni siquiera code-hints ), y el testeo y debugeo tampoco es particularmente fácil. Eso sí, poderse, lo que es poderse, se puede.

También quiero quedar claro que yo no he inventado nada, sino que he seguido las instrucciones que he encontrado en otros sitios ( el link puede requerir registro, por si acaso, también se puede seguir este link ), aunque sí he tenido que añadir mi granito de arena al proceso de instalación.

Veamos, pues, cómo desarrollar MIDlets con XCode.

En primer lugar hay que descargar el MPowerPlayer SDK. Una vez descargado y descomprimido, y para simplificar el proceso al máximo, hay que copiar la carpeta mpp-sdk en /Developer/Java. Este sdk no es más que una colección de jar contra la que compilar el proyecto, y un emulador en el que probarlo.

A continuación hay que cambiar los permisos de un archivo. El archivo en cuestión es el preverificador, y está en la carpeta /Developer/Java/mpp-sdk/osx/preverify/ y se llama preverify. Para darle permisos de ejecución, yo he tirado por el camino rápido y le he cambiado los permisos a 777:

chmod 777 preverify

El siguiente paso es instalar la plantilla de proyecto para XCode. La plantilla puede descargarse de aquí. Una vez descargado y descomprimido el archivo, hay que copiar la carpeta que se obtiene ( "Ant-based MIDlet Jar" ) en la carpeta /Librería/Application Support/Apple/Developer Tools/Project Templates/Java

Bien, pues ahora, hay que abrir XCode, crear un proyecto nuevo, elegir como tipo de proyecto Ant-based MIDlet jar ( dentro del grupo de proyectos java ), asignarle nombre ( sin espacios, y teniendo en cuenta que el nombre que se le dé al proyecto será el que se asignará a la clase principal ).

Y para terminar, el último paso. Si se intenta compilar tal cual, dará un error, ya que la ruta del preverificador en la tarea Ant no es correcta. Por tanto, en el build.xml habrá que cambiarla de "${mppdev}/osx/preverify" a "${mppdev}/osx/preverify/preverify".

Y ya sí, se puede compilar. La cosa funciona, pero sin code-hints en XCode ( lo cual, al menos para mí, que soy incapaz de aprenderme ninguna API es letal ), y con un emulador que en mi G4 utiliza casi el 50% del procesador. Pero algo es algo, supongo.

MPowerPlayer.jpg

Agosto 10, 2005

[Flash 8] El sol y su sombra

Arrastra el sol alrededor de la tierra y ver·s cÛmo la sombra que Èsta proyecta cambia. Necesitar·s la flash player 8 public beta




Para este ejemplo, he utilizado algunas de las nuevas clases de flash 8, como los filtros glow, dropshadow y bevel, asÌ como alguna de las nuevas clases para c·lculos geomÈtricos.

ACTUALIZACI”N 20/9/05: Descarga el cÛdigo fuente

Agosto 08, 2005

[Flash 8] Glow filter




Haz click en el fondo

Es necesario el flash player 8:
http://www.macromedia.com/software/flashplayer/public_beta/

ACTUALIZACI”N 20/9/05: Descarga el cÛdigo fuente

[Flash 8] Blur filter





Haz click en el fondo

ACTUALIZACI”N 20/9/05: Descarga el cÛdigo fuente

Anuncio oficial de la nueva versiÛn de Flash

Ya se ha anunciado la nueva versiÛn de flash, que se va a llamar Flash 8. TambiÈn se ha anunciado Dreamweaver 8, y Macromedia Studio 8.

Como la noticia estar· dando la vuelta a los blogs durante todo el dÌa, probablemente lo mejor sea ir directamente al MXNA y leer todos los posts sobre el tema.

En todo caso, lo m·s parecido a un anuncio oficial puede ser esto:

Studio 8 - It's official

Agosto 06, 2005

60 aÒos despuÈs

Hoy se cumplen 60 aÒos del lanzamiento del arma m·s destructiva de la historia de la humanidad.

En la BBC han preparado un especial ( que hace uso masivo de flash ) que incluye vÌdeos y grabaciones de la Època y testimonios de supervivientes.

Esepcial de la BBC
Via Barrapunto

Agosto 05, 2005

[Cocoa] Localization suite 2.0

Localization suite es un set de tres herramientas que facilitan el trabajo de localizar las aplicaciones Cocoa en varios idiomas.

Aunque el soporte multi-idioma del framework es bastante bueno, no siempre es fácil mantener las distintas versiones locales actualizadas, sobre todo si se van produciendo nuevos releases con frecuencia.

Por cierto, la suite es gratuita.

El fotograma en blanco y mis noches de insomnio.

Si recuerdan, aquÌ ,les explicaba el motor para el desarrollo de aventuras gr·ficas en Flash. Bien,entre aventuras, reediciones, traducciones, ..ya he perdido la cuenta del n˙mero de cdroms que han salido, todos sin problemas. ø Todos ?. No. El otro dÌa, un cdrom, empezÛ a dar problemas. Por requerimientos del proyecto, debe funcionar en un pentium II a 300Mhz. Termino de exportar el cdrom en mi m·quina ( Pentium IV ) y funciona perfÈctamente, pero al llevarlo a las m·quinas de testing ( Pentium II con W98, Pentium con Linex, Mac G3 ),fallaba en todas. Bueno, no es que fallase, es que iba muy muy lento. ø cu·l es el problema ? ø porquÈ si todos los cdroms funcionan bien, este da problemas ?.
Comienza la fase de an·lisis del problema, y se descarta problemas de la programaciÛn ( todos los cdroms llevan el mismo cÛdigo ) .
Como el cliente ha pedido unos cambios en unas animaciones, empiezo a pensar que uno de estos cambios en la animaciÛn de inicio o en la de fin del juego, hacen que algo falle. ASÌ pues, empiezo a probarlo sin una de las animaciones, sin la otra, sin ninguna de las dos, rehaciendo todo el fla desde cero, etc... ( Bien, hay que explicar, que cada prueba supone, exportar el fla, crear un instalador con zinc estudio, generar en una imagen ISO un disco hÌbrido pc/mac, sacarlo a disco fÌsico, ....en total cada cambio unos 45 minutos mÌnimo hasta poder probar en las m·quinas de testing ) y nada que no funciona.

Es entonces cuando me doy cuenta que nada m·s arrancar el cdrom, la primera pantalla que aparece, es la de login, y que al introducir tus datos, parece que incluso le cuesta aparecer en pantalla, es decir, escribo una "e" y como que pasan unos milisegundos hasta que aparece en pantalla. Lo justo para que parezca algo raro. AsÌ pues, se me ocurre que el problema puede estar en un swf que se carga nada m·s arrancar el cdrom con la configuraciÛn de los men˙s, los textos que se deben mostrar en todo el cdrom etc..( este swf se genera a partir de todos los xml con los que se desarrolla el juego ) . AsÌ pues le abro,y ........ el *+«?ø{ swf tenÌa dos frames, dos puÒeteros frames, el primer frame en el que se declaraban las 300 variables( de tipo XML ) de configuraciÛn y textos del cdrom , y un segundo fotograma vacÌo. Lo que hacÌa que se estuviesen definiendo esas 300 variables ( aproximadamente ) 6 veces por segundo, y claro, el juego se tostaba.

En fÌn, tras averiguar la causa del problema sÛlo se me ocurrÌa acordarme de la madre del F5, del fotograma de los...
AsÌ que la moraleja es...Tener cuidado con los fotogramas vacÌos, que uno sÛlo puede hacer que vuestras 8000 lÌneas de cÛdigo no sirvan para nada.

Agosto 04, 2005

Un ejemplo del patrÛn memento ( la versiÛn actionscript )

Conquistar el mundo no es f·cil. Nada f·cil. Yo lo sÈ, t˙ lo sabes, incluso el Profesor Dispar lo sabe.

El Profesor se siente preparado para llevar a cabo su malvado plan. Tiene el conocimiento teÛricos, tiene los conocimientos pr·cticos, tiene un plan, tiene hasta unas gafas de sol nuevas, pero °hay tantos detalles que pulir antes de lanzarse a la conquista del mundo!.

En episodios anteriores, hemos visto cÛmo el Profesor ha implementado el patrÛn prototype ( para crear su ejÈrcito de clones -°anda, acabo de caer!- ), el patrÛn extensiÛn objects ( para asignarles sus roles ), el patrÛn command ( para asignarles las Ûrdenes ), y el patrÛn observer ( para implementar el sistema de comunicaciones ). Parece que el Profesor Dispar ha estado bastante ocupado implementando patrones, pero ha sido suficiente?. NO!! ( muhahahahahahhaha ).

Si recuerdas el post sobre el patrÛn observer ( cosa que dudamos mucho, porque nosotros ya no nos acordamos ), dejamos a las vacas y las ovejas en el instante previo al ataque final ( mientras el Profesor reÌa como un histÈrico ). Est·n esperando ( insÈrtese aquÌ m˙sica heroica, por favor, en dram·tico crescendo ) a recibir la orden de ataque. Cada vaca, cada oveja, est· alerta, escuchando la radio, esperando escuchar la seÒal secreta, para abandonar su posiciÛn y lanzarse a cumplir las Ûrdenes recibidas.

El Profesor Dispar est· a punto de presionar el botÛn de "atacar", cuando de repente se da cuenta de que algo no est· bien ( y la m˙sica heroica se apaga ). ìøQuÈ pasa si me veo obligado a dar la orden de retirada a mis tropas?. No es que mi plan vaya a fallar ( despuÈs de todo soy un genio del mal ), pero ya se sabe, no se puede confiar en los subordinados, y quÈ pasa si tengo que cancelar el ataque cuando mis huestes ya han comenzado a avanzar ( glorioso avance, por supuesto )?î.

Ciertamente, el Profesor Dispar es un genio. Se ha dado cuenta de un sutil ìbugî en su plan. øQuÈ pasa si tiene que dar la orden de cancelar el ataque cuando sus tropas ya han abandonado su posiciÛn inicial?. Bueno, ha implementado un mecanismo de comunicaciones, asÌ que puede mandar la seÒal secreta de retirada, øno?. ( muhahahahahah, ya sabes ). Pero hay un problema: la vacas y las ovejas son conocidas por su notoria falta de memoria ( peor incluso que los peces ). Claro, que tambiÈn son conocidas por la calidad de los quesos que se producen con su leche, pero eso est· fuera del alcance de este tutorial.

La cuestiÛn es complicada. Una vaca no tiene memoria. Una oveja no tiene memoria. Punto-pelota. SÛlo pueden recordar una cosa a la vez. Por tanto, pueden recordar que tienen que atacar, que tienen que moverse hacia alg˙n lugar, pero en cuanto se meten esa informaciÛn en la mollera no son capaces de recordar nada m·s ( como, por ejemplo, dÛnde estaban cinco minutos antes, o si le habÌan pedido dinero prestado a alguien ).

Dicho de otra forma, el Profesor Dispar les puede decir que vuelvan a su posiciÛn original, pero eso no va a servir de nada, porque no se acuerdan de cu·l era su posiciÛn original.

memento1.jpg

Peeeeeero ( y vuelve a empezar la m˙sica heroica ), el Profesor Dispar recuerda vagamente, como entre una nebulosa, sus tiempos mozos de estudiante, cuando en su clase explicaron el patrÛn memento.

øQuÈ pasarÌa si cada oveja y cada vaca fuera capaz de escribir en un cuaderno ( cada una en su cuaderno, ser· por dineroÖ ) su posiciÛn inicial, y entregara ese cuaderno a su Sargento?. øY si el Sargento guardara esos cuadernos, y se los entregara a sus propietarios si los propietarios tuvieran que volver a las posiciones iniciales?. °Problema resuelto! ( muhahahahahahah ). °Es perfecto!. Las ovejas y las vacas sÛlo tendr·n que recordar una posiciÛn ( la posiciÛn hacia la que se supone que tiene que ir, sin importar si est·n atacando o est·n en retirada ), mientras una entidad externa les guardar· la informaciÛn que necesitar·n para retirarse.

memento2.jpg

øPero cÛmo puede la oveja guardar su informaciÛn relevante en un cuaderno?. F·cil ( aparte de las limitaciones fisiolÛgicas propias de su condiciÛn ). Cada oveja ser· responsable de crear una instancia de la clase en la que se va a guardar su informaciÛn interna, y la guardar· y despuÈs se la pasar· a su sargento.

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

La clase Sheep

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

Y finalmente, el sargento:

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

°Un momento!. El Profesor se ha dado cuenta de que hay un punto dÈbil en su plan. Si el Sargento guarda los cuadernos con las posiciones iniciales de las ovejas, hay riesgos de seguridad. øQuÈ pasa si los pesados del enemigo roban esa informaciÛn?. °°O incluso peor!!. øY si los pesados del enemigo no roban esa informaciÛn, pero la sustituyen por informaciÛn falsa?. °Un momento!. Si la informaciÛn contenida en los cuadernos estuviera encriptada, o sÛlo fuera accesible por las ovejas, °el problema estarÌa resuelto, nadie podrÌa cambiarla!.

Por tanto, para evitar posibles cambios en esa informaciÛn, el Profesor va a tomar dos medidas dr·sticas. Por un lado, todos los valores guardados en la clase SheepMemento sÛlo se podr·n asignar a travÈs del constructor. De ese modo, el Profesor se asegura que sÛlo se podr·n asignar al crear la clase, y nunca despuÈs.

Pero desgraciadamente, no es suficiente ( es tan difÌcil conseguir un buen plan ). El Profesor Dispar quiere evitar que la informaciÛn guardada en el memento sea modificada. De hecho, quiere que sÛlo sea una oveja la que pueda crear su memento correspondiente, y asignar sus valores. De esa forma, puede asegurarse de que nadie modifique esa informaciÛn.

Hacer eso en Java es bastante f·cil. Basta con colocar la clase SheepMemento en el mismo package que la clase Sheep, y hacer tanto su constructor como sus variables de clase protected. De esa forma, sÛlo pueden crear instancias de esa clase otras clases que estÈn en su mismo paquete.

Pero hacer lo mismo en actionscript no es tan f·cil. No existe el modificador ìprotectedî ( ni su funcionalidad ). ( se para la m˙sica heroica )

El Profesor Dispar ( la m˙sica heroica comienza de nuevo ) es un programador flash y lo ha sido durante muchos aÒos, asÌ que su capacidad para buscar soluciones a los problemas irresolubles es legendaria. Por tanto, enseguida encuentra una posible soluciÛn. øPero cÛmo?. El Profesor piensa: ìsi la oveja pasa una referencia a sÌ misma cuando crea el memento, puede chequear esa referencia otra vez cuando tiene que volver a su estado anterior, y de esa forma asegurar que ha sido ella la que creÛ el memento que se le pasaî ( muhahahahahahhahahaha ). Se lo intenta explicar a la oveja, pero ya se sabe, hay veces que si quieres hacer algo bien, lo tienes que hacer t˙ mismoÖ

Por tanto, cambia la forma en la que la oveja crea el memento, y la forma en la que vuelve a su estado anterior a partir de la informaciÛn guardada en el mismo ( que es la parte m·s importante ). Antes de devolver los datos correspondientes, se chequea si quien pide esos datos es el mismo que el que creÛ el memento. Si lo es, se devuelven datos, y si no lo es, dice ìbeeeeeî ( la cosa no da para m·s ).

Por tanto, finalmente la cosa quedar· asÌ ( lo primero de todo, la clase SheepMemento ):

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

La clase Sheep:

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

Y el sargento:

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

Muhahahahahahhaha. °°El Profesor Dispar lo ha conseguido de nuevo!!. Ha sido capaz de encapsular el estado interno de un objeto en otro objeto distinto, y encapsularlo tan bien que ese segundo objeto sÛlo puede ser utilizado por el objeto que lo creÛ ( quien sea capaz de repetir la frase tendr· mi eterna admiraciÛn ).

SÛlo una cosa m·s. øQuÈ te parece la forma en la que el Profesor ha implementado el chequeo de la identidad de la oveja?. øTe gusta la soluciÛn?.

En principio podrÌa resolverse tambiÈn de la siguiente forma: en vez de guardar en el memento una referencia al creador del mismo, se puede guardar el id del creador, o un hashcode de ese objeto, o algo similar. øAlguna idea?

Un ejemplo del patrÛn memento ( la versiÛn java )

Conquistar el mundo no es f·cil. Nada f·cil. Yo lo sÈ, t˙ lo sabes, incluso el Profesor Dispar lo sabe.

El Profesor se siente preparado para llevar a cabo su malvado plan. Tiene el conocimiento teÛricos, tiene los conocimientos pr·cticos, tiene un plan, tiene hasta unas gafas de sol nuevas, pero °hay tantos detalles que pulir antes de lanzarse a la conquista del mundo!.

En episodios anteriores, hemos visto cÛmo el Profesor ha implementado el patrÛn prototype ( para crear su ejÈrcito de clones -°anda, acabo de caer!- ), el patrÛn extensiÛn objects ( para asignarles sus roles ), el patrÛn command ( para asignarles las Ûrdenes ), y el patrÛn observer ( para implementar el sistema de comunicaciones ). Parece que el Profesor Dispar ha estado bastante ocupado implementando patrones, pero ha sido suficiente?. NO!! ( muhahahahahahhaha ).

Si recuerdas el post sobre el patrÛn observer ( cosa que dudamos mucho, porque nosotros ya no nos acordamos ), dejamos a las vacas y las ovejas en el instante previo al ataque final ( mientras el Profesor reÌa como un histÈrico ). Est·n esperando ( insÈrtese aquÌ m˙sica heroica, por favor, en dram·tico crescendo ) a recibir la orden de ataque. Cada vaca, cada oveja, est· alerta, escuchando la radio, esperando escuchar la seÒal secreta, para abandonar su posiciÛn y lanzarse a cumplir las Ûrdenes recibidas.

El Profesor Dispar est· a punto de presionar el botÛn de "atacar", cuando de repente se da cuenta de que algo no est· bien ( y la m˙sica heroica se apaga ). ìøQuÈ pasa si me veo obligado a dar la orden de retirada a mis tropas?. No es que mi plan vaya a fallar ( despuÈs de todo soy un genio del mal ), pero ya se sabe, no se puede confiar en los subordinados, y quÈ pasa si tengo que cancelar el ataque cuando mis huestes ya han comenzado a avanzar ( glorioso avance, por supuesto )?î.

Ciertamente, el Profesor Dispar es un genio. Se ha dado cuenta de un sutil ìbugî en su plan. øQuÈ pasa si tiene que dar la orden de cancelar el ataque cuando sus tropas ya han abandonado su posiciÛn inicial?. Bueno, ha implementado un mecanismo de comunicaciones, asÌ que puede mandar la seÒal secreta de retirada, øno?. ( muhahahahahah, ya sabes ). Pero hay un problema: la vacas y las ovejas son conocidas por su notoria falta de memoria ( peor incluso que los peces ). Claro, que tambiÈn son conocidas por la calidad de los quesos que se producen con su leche, pero eso est· fuera del alcance de este tutorial.

La cuestiÛn es complicada. Una vaca no tiene memoria. Una oveja no tiene memoria. Punto-pelota. SÛlo pueden recordar una cosa a la vez. Por tanto, pueden recordar que tienen que atacar, que tienen que moverse hacia alg˙n lugar, pero en cuanto se meten esa informaciÛn en la mollera no son capaces de recordar nada m·s ( como, por ejemplo, dÛnde estaban cinco minutos antes, o si le habÌan pedido dinero prestado a alguien ).

Dicho de otra forma, el Profesor Dispar les puede decir que vuelvan a su posiciÛn original, pero eso no va a servir de nada, porque no se acuerdan de cu·l era su posiciÛn original.

memento1.jpg

Peeeeeero ( y vuelve a empezar la m˙sica heroica ), el Profesor Dispar recuerda vagamente, como entre una nebulosa, sus tiempos mozos de estudiante, cuando en su clase explicaron el patrÛn memento.

øQuÈ pasarÌa si cada oveja y cada vaca fuera capaz de escribir en un cuaderno ( cada una en su cuaderno, ser· por dineroÖ ) su posiciÛn inicial, y entregara ese cuaderno a su Sargento?. øY si el Sargento guardara esos cuadernos, y se los entregara a sus propietarios si los propietarios tuvieran que volver a las posiciones iniciales?. °Problema resuelto! ( muhahahahahahah ). °Es perfecto!. Las ovejas y las vacas sÛlo tendr·n que recordar una posiciÛn ( la posiciÛn hacia la que se supone que tiene que ir, sin importar si est·n atacando o est·n en retirada ), mientras una entidad externa les guardar· la informaciÛn que necesitar·n para retirarse.

memento2.jpg

øPero cÛmo puede la oveja guardar su informaciÛn relevante en un cuaderno?. F·cil ( aparte de las limitaciones fisiolÛgicas propias de su condiciÛn ). Cada oveja ser· responsable de crear una instancia de la clase en la que se va a guardar su informaciÛn interna, y la entregar· a su sargento.

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

°Un momento!. El Profesor se ha dado cuenta de que hay un punto dÈbil en su plan. Si el Sargento guarda los cuadernos con las posiciones iniciales de las ovejas, hay riesgos de seguridad. øQuÈ pasa si los pesados del enemigo roban esa informaciÛn?. °°O incluso peor!!. øY si los pesados del enemigo no roban esa informaciÛn, pero la sustituyen por informaciÛn falsa?. °Un momento!. Si la informaciÛn contenida en los cuadernos estuviera encriptada, o sÛlo fuera accesible por las ovejas, °el problema estarÌa resuelto, nadie podrÌa cambiarla!.

Por tanto, para evitar posibles cambios en esa informaciÛn, el Profesor va a tomar dos medidas dr·sticas. Por un lado, todos los valores guardados en la clase SheepMemento sÛlo se podr·n asignar a travÈs del constructor. De ese modo, el Profesor se asegura que sÛlo se podr·n asignar al crear la clase, y nunca despuÈs.

package sheep; public class SheepMemento { private int serialNumber; private String location; public SheepMemento( int serial, String loc ) { serialNumber = serial; location = loc; } }

Pero desgraciadamente, no es suficiente ( es tan difÌcil conseguir un buen plan ). El Profesor Dispar quiere evitar que la informaciÛn guardada en el memento sea modificada. De hecho, quiere que sÛlo sea una oveja la que pueda crear su memento correspondiente, y asignar sus valores. De esa forma, puede asegurarse de que nadie modifique esa informaciÛn.

Hacer eso en Java es bastante f·cil. Basta con colocar la clase SheepMemento en el mismo package que la clase Sheep, y hacer tanto su constructor como sus variables de clase protected. De esa forma, sÛlo pueden crear instancias de esa clase otras clases que estÈn en su mismo paquete.

Por tanto, el package sheep contendr· las siguientes clases:

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

La clase SheepMemento:

package sheep; public class SheepMemento { protected int serialNumber; protected String location; protected SheepMemento( int serial, String loc ) { serialNumber = serial; location = loc; } }

Y finalmente, el sargento:

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

Muhahahahahahhaha. °°El Profesor Dispar lo ha conseguido de nuevo!!. Ha sido capaz de encapsular el estado interno de un objeto en otro objeto distinto, y encapsularlo tan bien que ese segundo objeto sÛlo puede ser utilizado por el objeto que lo creÛ ( quien sea capaz de repetir la frase tendr· mi eterna admiraciÛn ).