« Un ejemplo el patrÛn observer (la versiÛn actionScript) | Inicio | Resumen de novedades del .Net framework 2.0 »

Un ejemplo del patrÛn observer (la versiÛn Java)

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.

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Ì

public interface IObserver { public void update(Message info); }

public interface ISubject { public void addObserver(IObserver obs); public void removeObserver( IObserver obs ); public void notifyObserver( ); }

public class Cow implements IObserver { public Cow( ) { debug("Soy una vaca muuuuuu| I am a cow Muuuu"); } private void debug( String arg ) { System.out.println("Vaca | Cow :-> "+arg ); } public void update( Message msg ) { debug("Actualizada | update "); String kk = msg.getMsg(); debug("msgText: "+kk ); } }

public class Sheep implements IObserver { public Sheep( ) { debug("creada la oveja | a new sheep"); } private void debug( String arg ) { System.out.println("Oveja |Sheep :-> "+arg ); } public void update( Message msg ) { debug("Actualizada | update "); String kk = msg.getMsg(); debug("msgText: "+kk ); } }

El mensaje:

public class Message { String msg = ""; public void setMsg( String arg ) { this.msg = arg; } public String getMsg( ) { return this.msg; } }

public class Profesor implements ISubject { private ArrayList misObservers; private Message miMsg; public Profesor( ) { //System.out.println("profesor profesor"); debug("Creando al profesor | a new Profesor"); misObservers = new ArrayList(); } public void debug( String arg ) { System.out.println("Profesor:-> "+arg); } public void addObserver( IObserver obs ) { debug("aÒadido observer | a new observer"); misObservers.add(obs); debug("Ya tengo | I have: "+misObservers.size()+" observers "); } public void removeObserver( IObserver obs) { debug("eliminado observer | removing observer"); //int value = indexOf misObservers.remove(misObservers.indexOf(obs)); debug("ahora me quedan | now i have : "+misObservers.size()+" observers "); } public void notifyObserver( ) { debug("notificar observers | notify observer "); miMsg = new Message( ); miMsg.setMsg("In the Navy"); for( int i = 0; i < misObservers.size(); i++ ) { IObserver obs = ( IObserver )misObservers.get(i); obs.update( miMsg ); } } }

Y para finalizar

public class ObserverSample { public static void main(String[] args) { Profesor prof = new Profesor(); Sheep oveja = new Sheep(); Cow vaca = new Cow(); Sheep oveja2 = new Sheep( ); Cow vaca2 = new Cow( ); Sheep oveja3 = new Sheep(); Cow vaca3 = new Cow(); prof.addObserver( oveja ); prof.addObserver( oveja2 ); prof.addObserver( oveja3 ); prof.addObserver( vaca ); prof.addObserver( vaca2 ); prof.addObserver( vaca3 ); prof.removeObserver(oveja); prof.notifyObserver( ); } }

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Ì:

public interface ISubject { public void addObserver(IObserver obs); public void removeObserver( IObserver obs ); public void notifyObserver( Message msg ); public void requestInfo( String arg ); }

public class Cow implements IObserver { public Cow( ) { debug("Soy una vaca | I am a cow "); } private void debug( String arg ) { System.out.println("Vaca | Cow :-> "+arg ); } public void update( Message info ) { debug("Actualizada | update "); debug(" -> "+ info.getMsg()); } }

public class Sheep implements IObserver { private ISubject profesor; public Sheep(ISubject isub ) { debug("creada la oveja | a new Sheep"); this.profesor = isub; this.profesor.addObserver(this); this.profesor.requestInfo( "Rasputin" ); } private void debug( String arg ) { System.out.println("Oveja | Sheep:-> "+arg ); } public void update( Message info ) { debug("Actualiz·ndome | update"); debug( " -> "+info.getMsg()); } }

import java.util.ArrayList; public class Profesor implements ISubject { private ArrayList misObservers; public Profesor( ) { //System.out.println("profesor profesor"); debug("Creando al profesor | a new profesor"); misObservers = new ArrayList(); } public void debug( String arg ) { System.out.println("Profesor :-> "+arg); } public void addObserver( IObserver obs ) { debug("a“adido observer | a new observer"); misObservers.add(obs); debug("Ya tengo | I have: "+misObservers.size()+" observers "); } public void removeObserver( IObserver obs) { debug("eliminado observer | removing observer"); misObservers.remove(misObservers.indexOf(obs)); debug("ahora me quedan | now i have: "+misObservers.size()+" observers "); } public void notifyObserver(Message msg ) { debug("notificar observers | notify observers"); for( int i = 0; i < misObservers.size(); i++ ) { IObserver obs = ( IObserver )misObservers.get(i); obs.update( msg ); } } public void requestInfo( String arg ) { debug("recibiendo una peticiÛn | someone has asked for ..."); Message msg = new Message( ); msg.setMsg( arg ); this.notifyObserver( msg ); } }

Y por fin:

public class ObserverSample { public static void main(String[] args) { Profesor dispar = new Profesor(); Sheep oveja = new Sheep( dispar ); } }

Evidentemente, el profesor, que ha estudiado la API de JAVA, sabe que existe la clase java.util.Observable y la interface java.util.Observer. La primera no la ha utilizado, pues eso implicarÌa que el profesor ( el mismo ) extiende o hereda de Observable. Esto podrÌa ser posible, pero en realidad el profesor extiende de una larga extirpe de profesores diabÛlicos empeÒados en conquistar el mundo, y ni quiere ni puede extender de Observable. ( class Profesor extends ExtirpeDeProfesores, Observable -> no es posible ) Por eso ha decidido construirse su propia interface ISubject. Con respecto a la interface java.util.Observer, sÌ la podrÌa haber utilizado para que sus vacas y ovejas la implementasen en lugar de implementar IObserver, pero ya saben, los genios del mal, ellos se lo guisan y ellos se lo comen.

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/697

Comentarios

Excelente como siempre... didactico y creativo. Buen punto eso de incluir el cÛdigo fuente.

Gracias