An example of the Observer pattern (the java version)
First of all, remember: Professor Coupling is crazy, but he’s not an idiot. He knows that maybe, his evil plan has some weak points, that maybe, there could be some mistakes. And he also knows that sometimes it’s better to go back to the starting point to gather some strength and launch a new attack ( well, you know, it’s not easy to conquer the world ). He wants to be able to tell his troops to cancel the attack if something goes wrong ( you know, please insert some hysterical laughs here ) .
So, he has equipped his troops with the newest model of EnigmaRadio ( enigmawoot!!??? ). The EnigmaRadio is the last invention of Professor Coupling’s evil genius, and basically it’s, well, a radio receiver, that is cheaper than an iPod. Not as cool as an iPod, but cheaper.
But why? Why would a sheep or a cow need a radio?. Well, conquering-the-world-battles are noisy. It’s not easy to communicate with your troops when you are in the middle of such destruction. There’s noise, there’s dust, fog… In fact, sometimes, you might be thinking that you are giving an order to a sheep, but you are talking to a cow. Well, a complete mess. And, of course, Professor Coupling is aware of all these communication problems.
Professor Coupling has been using his evil genius to find a solution. The solution he has found ( muhhhahahahahahah ) has been to assign a cow the responsibility of propagating his orders. In plain English, there will be a cow ( Corporal Cow ) whose duty will be to run all the way to the trenches, and then, one by one, give all the cows and sheeps the new orders. Brilliant!!!!.
Well, not so brilliant. What if someone kills ( sorry, gratuite violence again ) Corporal Cow when he still hasn’t given the new orders to all the soldiers?.
And so, Professor Coupling, once again, remembered when he was a young student, and the happy times when he studied the Observer pattern.
That’s why Professor Coupling, who is crazy but is not an idiot, has equipped all his troops with the latest model of the EnigmaRadio. The EnigmaRadio will we tuned to BBC Radio 4 ( why not? ). So, his troops will charge against the enemy with their radios switched on, and as soon as they hear "In the navy", by Village People, they will now that it’s time to go back to their starting position.
Dj Coupling broadcasting his program
The code will be something like this:
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 );
}
}
The message:
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 );
}
}
}
And finally
public class ObserverSample
{
public static void main(String[] args)
{
Profesor prof = new Profesor();
Sheep firstSheep = new Sheep();
Cow firstCow = new Cow();
Sheep secondSheep = new Sheep( );
Cow secondCow = new Cow( );
Sheep thirdSheep = new Sheep();
Cow thirdCow = new Cow();
prof.addObserver( firstsheep );
prof.addObserver( secondSheep );
prof.addObserver( thirdSheep );
prof.addObserver( firstCow );
prof.addObserver( secondCow );
prof.addObserver( thirdCow );
prof.removeObserver( firstSheep );
prof.notifyObserver( );
}
}
Muhahahahahahhahahahaha ( almost half an hour of hysterical laughs ). Professor Coupling has found a quick and reliable way of sending messages to his troops. It’s perfect!! Well, really?. Maybe it’s not so perfect.
Imagine that, for instance, Professor Coupling wants his soldiers to report back when they receive the new orders. Or imagine that Professor Coupling can infiltrate a sheep into the enemy’s headquarters. That spy could not communicate with Professor Coupling to tell him when the perfect moment to launch the attack comes!!!.
But, Professor Coupling, who is crazy but is not an idiot, has previously thought about it, and has decided to implement a mechanism in the EnigmaRadio that could serve his troops to communicate back with him. So, the spy sheep, as soon as it discovers the enemy’s weakest point, could phone the EnigmaRadio base station and ask them to broadcast Boney M’s "Rasputin" ( their secret "attttttaaaaaaaaaaaaaack" signal ). So, when Professor Coupling’s troops hear "Rasputin" through their EnigmaRadio, they will know that the moment has come, that it will be the moment to launch the final attack.
A sheep singing "In the Navy"
So, Professor Coupling will have to change his code a bit ( but he doesn’t care, listen: "Muhahahahahahahaaaaa" ). He will start adding a new method ( requestInfo ) to the ISubject interface . That method will allow his radio station to receive the telephone calls from the Spy Sheep. He has also changed the constructor of the Cow and Sheep classes.
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 );
}
}
And finally:
public class ObserverSample
{
public static void main(String[] args) {
Profesor dispar = new Profesor();
Sheep oveja = new Sheep( dispar );
}
}
A quick note: Professor Coupling knows about the existance of the java.util.Obervable class and the java.uti.Observer interface. But he didn't want to extend Obervable, because he extends a long list of evil geniuses. That's why he has decided to build his own ISubject interface. He could have used the Oberver interface as the base class for the cows and sheep, but you know, that's the way evil geniuses are...
All these classes have been simplified to the maximum, because we just wanted to show how the pattern works, and to show that Professor Coupling is an evil genius, but he’s not an idiot ( the image fades to black, and "The End" appears ).
And remember, Professor Coupling is spanish, and a bit lazy, so he's left some comments in his mother tongue...
You can download the source code here