« CÛmo utilizar los patrones de diseÒo | Inicio | Un ejemplo del patrÛn observer (la versiÛn Java) »

Un ejemplo el patrÛn observer (la versiÛn actionScript)

Est· desencadenado. El primer ataque ha sido lanzado. El profesor Dispar ha dado las Ûrdenes a sus huestes para dominar el mundo. En post anteriores hemos visto como el profesor Dispar ha conseguido clonar cualquier animal ( con gran predilecciÛn por ovejas y vacas ) utilizando un patrÛn prototype, ha conseguido darlas un rol din·micamente con el patrÛn extension objects, y ha repartido las Ûrdenes con un patrÛn command.

Pero como ya sabemos, el profesor Dispar est· loco, pero no es idiota. Sabe, que algo puede salir mal, que un pequeÒo detalle puede truncar sus planes de dominar el mundo. Y tambiÈn sabe que una retirada a tiempo es una victoria.

AsÌ, pues, ha equipado a sus huestes de una radioenigma de campaÒa ( es decir, una radio acompaÒada de una m·quina enigma ). Pero, ø porquÈ ha hecho esto ?. Sencillo, en el fragor de la batalla, las comunicaciones directas se hacen complicadas. Es difÌcil hacer llegar las Ûrdenes, y muchas veces no se tiene claro a quien le estamos dando esas Ûrdenes ( øser· una vaca?, ø ser· una oveja? ).Conquistar el mundo no es f·cil, de hecho muchos lo han intentado pero no lo han conseguido. El profesor Dispar, ha estudiado con detenimiento todas las intentivas anteriores para no reproducir los mismos errores. ø QuÈ pasarÌa si para dar nuevas Ûrdenes, el profesor necesitase que el sargento vaca tuviese que recorrerse la trinchera indicando una por una a todas las vacas y ovejas que se retirasen ?. Desde que le diese la orden a la primera, hasta que se la diese a la ˙ltima, pasarÌa un tiempo precioso. Adem·s, ø y si ocurre algo por el camino ?. Todos hemos jugado al f˙tbol de pequeÒos despuÈs de comer, y sabemos lo que ocurre cuando te pones a correr. Se llama flato. Si nos pasa a nosotros que tenemos un estÛmago, imaginemos las posibilidades que hay de que le pase al sargento vaca que tiene 4. Las posibilidades de que las Ûrdenes no lleguen a todos los integrantes de nuestra tropa son amplias.

Sabiendo esto, el profesor Dispar, que est· loco pero no es idiota, para poder modificar ( actualizar ) f·cil y r·pidamente el comportamiento de sus huestes, utilizar· el patrÛn Observer.

Como el profesor Dispar no es idiota ( aunque este loco y sea un genio del mal, no es idiota ), ha encontrado una malvada forma de enviar las Ûrdenes a sus tropas. Las ovejas y vacas, estar·n equipadas con una radio que sintoniza Cadena Dial ( sÌ, entendemos que es desagradable, pero dominar el mundo tiene estas cosas ). Sus tropas estar·n atentas a la radio, y cuando esta emita una canciÛn de Village People, la m·quina enigma les indicar· quÈ acciÛn deben tomar.

enigmaBroadcaster.jpg
Dj Dispar emitiendo su programa

El cÛdigo ser· algo asÌ

interface IObserver { public function update( info: Object ): Void; }

interface ISubject { public function addObserver( obs: IObserver ) : Boolean; public function removeObserver( obs: IObserver ) : Boolean; public function notifyObserver( info: Object ) : Void; }

class Cow implements IObserver { function Cow( ) { this.init( ); } private function debug( arg: String ): Void { trace( "Vaca | Cow: ->"+arg ); } private function init( ): Void { debug( "init" ); } public function update( info: Object ) : Void { debug( "La emisora del profesor ha emitido | song in the radio is: "+info.cancion ); debug( enigmaResult( info.cancion ) ); } private function enigmaResult( arg: String ): String { debug( "soy la m·quina enigma interpretando quÈ hacer | I am the enigma machine" ); if( arg != "In the Navy" ) { return "sigo a lo mÌo. MUUU | nothing to do MUUUUU"; } else { return "cielos, llegÛ el momento. MUUUUUUUUUUU | Oh, my God, it's the signal MUUU"; } } }

class Sheep implements IObserver { function Sheep( ) { this.init( ); } private function debug( arg: String ): Void { trace( "Oveja | Sheep: ->"+arg ); } private function init( ): Void { debug( "init" ); } public function update( info: Object ) : Void { debug( "La emisora del profesor ha emitido | song in the radio is: "+info.cancion ); debug( enigmaResult( info.cancion ) ); } private function enigmaResult( arg: String ): String { debug( "soy la m·quina enigma interpretando quÈ hacer | I am the enigma machine" ); if( arg != "In the Navy" ) { return "sigo a lo mÌo. BEEEEE | nothing to do BEEEEEE"; } else { return "cielos, llegÛ el momento. BEEEE | Oh, my God, it's the signal BEEEEEE"; } } }

class Profesor implements ISubject { private var arrayObservers: Array; function Profesor( ) { init( ); } private function debug( arg: String ) : Void { trace("Profesor: ->"+arg); } private function init( ): Void { debug( "init" ); this.arrayObservers = new Array(); } public function addObserver( obs: IObserver ): Boolean { // AquÌ comprobamos que el observer que estamos intentando aÒadir, no est· ya en el array de // observers. En caso que estÈ, no lo aÒadiremos y retornaremos false. En caso que no estÈ, // lo aÒadimos y retornamos true. debug("registrando"); this.arrayObservers.push( obs ); return true; } public function removeObserver( obs: IObserver ) : Boolean { // comprobamos que el observer a eliminar est· en el array. Que no est·, retornamos false, que est· // lo eliminamos y retornamos true var longObservers: Number = this.arrayObservers.length; for ( var k: Number = 0; k< longObservers; k++ ) { var tmpObserver: IObserver = this.arrayObservers[ k ]; if( tmpObserver == obs ) { this.arrayObservers.splice( k, 1 ); break; } } return true; } public function notifyObserver( info: Object ): Void { var longObservers: Number = this.arrayObservers.length; for ( var k: Number = 0; k

Y en el primer frame del fla

var pd: Profesor = new Profesor(); var miVaca: Cow = new Cow( ); var miOveja: Sheep = new Sheep( ); pd.addObserver( miVaca ); pd.addObserver( miOveja ); var info:Object = new Object(); info.cancion = "In the Navy"; pd.notifyObserver( info );

De este modo, el profesor, puede comunicar r·pidamente con todas sus tropas. Es brillante, es genial, es maravilloso, es....ø perfecto ?. Bueno, la verdad es que est· muy bien, pero imaginemos, por un momento una situaciÛn en la que una oveja consigue infiltrarse en el alto mando enemigo, y descubre que los enemigos est·n a punto de ser derrotados, y en ese momento de extasis, la radio emite "In the Navy" indicando a las tropas que hay que retirarse. NOOOOOOOOO ( bueno, esto est· traducido, claramente la oveja dirÌa algo como BEEEEEEEEEEE ). Nuestra oveja espÌa, tiene una informaciÛn valiosÌsima, pero que no puede comunicar a su alto mando, porque la forma de transmisiÛn es ˙nicamente de tipo push, del profesor a sus tropas, no hay retorno. Que situaciÛn, la oveja necesita transmitir que el ataque debe continuar pero....

enigmaReceiver.jpg
Una oveja tarareando "In the Navy"

ajajajajajajajaj, el profesor Dispar ( loco pero no tonto ) ha pensado en ello, y ha decidido implementar un patrÛn observer que permita la transmisiÛn tipo push ( del sujeto emisor a todos los sujetos receptores ) y tipo pull ( uno de los objetos receptores, puede solicitar una informaciÛn al objeto emisor para que este la envÌe a todos los dem·s ). AsÌ, nuestra oveja espÌa, estar· equipada de un n˙mero de telÈfono al que podr·n llamar y solicitar que emitan "Rasputin" de Boney M, y cuando esta canciÛn sea emitida por la radio, las ovejas y vacas que la escuchen, sabr·n que ha llegado el momento de la ofensiva final. JAJAJAJAJAJAJAJA. Para ello debemos modificar ligeramente nuestros cÛdigos anteriores.

Para empezar nuestro sujeto, implementar· un nuevo mÈtodo que hemos aÒadido a la interfaz ISubject( requestInfo ), que permitir· recibir las llamadas telefÛnicas de la oveja espÌa.Vemos tambiÈn que el constructor de las ovejas y las vacas tambiÈn ha cambiado un poco. Ahora las ovejas y vacas, almacenar·n una referencia al constructor. TambiÈn hemos modificado el cÛdigo de nuestra oveja ( suponemos que esta es la oveja espÌa en el momento en que decide que pese a lo que emite la radio, hay que atacar y pide que se emita Rasputin que es otra seÒal de ataque ).

Por tanto, la interfaz ISubject quedar· asÌ:

interface ISubject { public function addObserver( obs: IObserver ) : Boolean; public function removeObserver( obs: IObserver ) : Boolean; public function notifyObserver( info: Object ) : Void; public function requestInfo( arg: String ): Void }

class Cow implements IObserver { private var profesor: Profesor; function Cow( prof: Profesor ) { this.profesor = prof; this.profesor.addObserver(this); this.init( ); } private function debug( arg: String ): Void { trace( "Vaca | Cow: ->"+arg ); } private function init( ): Void { debug( "init" ); } public function update( info: Object ) : Void { debug( "La emisora del profesor ha emitido | song in the radio is: "+info.cancion ); debug( enigmaResult( info.cancion ) ); } private function enigmaResult( arg: String ): String { debug( "soy la m·quina enigma interpretando quÈ hacer | I am the enigma machine" ); if( arg != "In the Navy" && arg!="Rasputin" ) { return "sigo a lo mÌo. MUUU | nothing to do MUUUUU"; } else { return "cielos, llegÛ el momento. MUUUUUUUUUUU | Oh, my God, it's the signal MUUU"; } } }

class Sheep implements IObserver { private var profesor: Profesor; function Sheep( prof: Profesor ) { this.profesor = prof; this.profesor.addObserver(this); this.init( ); } private function debug( arg: String ): Void { trace( "Oveja | Sheep: ->"+arg ); } private function init( ): Void { debug( "init" ); } public function update( info: Object ) : Void { debug( "La emisora del profesor ha emitido | song in the radio is: "+info.cancion ); debug( "enigmaResult: "+enigmaResult( info.cancion ) ); } private function enigmaResult( arg: String ): String { debug( "soy la m·quina enigma interpretando quÈ hacer | I am the enigma machine" ); if( arg != "In the Navy" && arg!="Rasputin" ) { debug("un momento, debemos atacar "); debug("wait a moment, we must attack"); debug("pedirÈ un ataque | I'll ask for an attack "); askForAttack( ); return "he solicitado un ataque | i've asked for an attack"; //return "sigo a lo mÌo. BEEEEE | nothing to do BEEEEEE"; } else { return "cielos, llegÛ el momento. BEEEE | Oh, my God, it's the signal BEEEEEE"; } } private function askForAttack( ): Void { this.profesor.requestInfo( "Rasputin" ); } }

class Profesor implements ISubject { private var arrayObservers: Array; function Profesor( ) { init( ); } private function debug( arg: String ) : Void { trace("Profesor: ->"+arg); } private function init( ): Void { debug( "init" ); this.arrayObservers = new Array(); } public function addObserver( obs: IObserver ): Boolean { // AquÌ comprobamos que el observer que estamos intentando aÒadir, no est· ya en el array de // observers. En caso que estÈ, no lo aÒadiremos y retornaremos false. En caso que no estÈ, // lo aÒadimos y retornamos true. debug("registrando"); this.arrayObservers.push( obs ); return true; } public function removeObserver( obs: IObserver ) : Boolean { // comprobamos que el observer a eliminar est· en el array. Que no est·, retornamos false, que est· // lo eliminamos y retornamos true var longObservers: Number = this.arrayObservers.length; for ( var k: Number = 0; k< longObservers; k++ ) { var tmpObserver: IObserver = this.arrayObservers[ k ]; if( tmpObserver == obs ) { this.arrayObservers.splice( k, 1 ); break; } } return true; } public function notifyObserver( info: Object ): Void { var longObservers: Number = this.arrayObservers.length; for ( var k: Number = 0; k

Y en el primer frame del fla:

var pd: Profesor = new Profesor(); var miVaca: Cow = new Cow( pd ); var miOveja: Sheep = new Sheep( pd ); var info:Object = new Object(); info.cancion = "Any song"; pd.notifyObserver( info );

Evidentemente, los cÛdigos est·n simplificados al m·ximo simplemente para ilustrar como es el patrÛn. Una vez m·s comprobamos que el profesor tiene sus planes muy bien estudiados, no es idiota ni tonto. SÛlo ø est· loco ?.....jajajajajajajajajaja ( ya saben, risas de ultratumba con el fundido a negro y el cartel de the end )

Si quieres, puedes bajar el cÛdigo fuente aquÌ

TrackBack

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