Today i wanna speak about a classic Design Pattern : Observer.
Observer is usually used when an object needs to be informed about other’s object state changing and, as general rule, in events management.
There are two actors: Subject and Observer.
Subject is object in whom Observer is interested in knowing changing state. Is such cases polling (regular interrogation about object’s state) is not the best solution.
Observer can register itself in Subject’s list of “notifiable objects” and Subject, on a particular event, can notify this to all his observers.
In my project i must to implement a kind of mailbox to store “application’s alarms”. Near the description of mailbox i must to show the number of alarms within it. Old implementation provide a (in my opinion) very expansive solution: on each page refreshing, to perform a count on database. This is a kind of polling on alarm’s table.
I thought that there are only 3 classes that cans add alarm in database. So why not implement an observer pattern? The 3 classes are my Subjects and alarms count is Observer. It is a little bit strange because in this case there is only one observer and three subjects. We can see this as three different Subject-Callback (when there is only a observer, this is called Callback).
When a class adds or removes an alarm, it notify this to my alarm’s count that can be increment or decrement the value.
Now i show a very simple examples to better understand Observer pattern.
There is a croupier generating a random number in 1..100 range and a player saying “YEAH” if number is a 3 multiple. On each generation croupier notify player on which number were extracted.
This is UML diagram:
The pattern is implemented in this way:
there is a Subject abstract class that implements two methods: addListner(Observer o) and removeListner(Observer o). The first one allows observers object to register themselves to Subject, and the other one to remove themselves. This behavior is generalized and all objects that extends this abstract class have that. The method notifyListner(int extractNumber) is abstract and must be implemented by extending objects. The concrete class NumberGenerator extends Subject and add a method: extractNumber, that generate a random number in range 1..100.
Interface Observer generalize behavior of all observers forcing them to implement update(int extractedNumber) method. This method is called by subjects on notify event. Concrete class ThreeChecker implements Observer interface and add a method exult() that simply print “YEAH” string on stdout.
This is source code:
package it.max.didato; import java.util.ArrayList; import java.util.List; // Abstract class extended by subject objects public abstract class Subject { //list of observers that subjects must notify List<Observer> observers = new ArrayList<Observer>(); //allow observer to register public void addListner(Observer o){ this.observers.add(o); } //allow observer to unregister public void removeListner(Observer o){ this.observers.remove(this.observers.indexOf(o)); } //abstract method to inform all observers public abstract void notifyListner(int extractedNumber); }
package it.max.didato; import java.util.Random; //extends Subject public class NumberGenerator extends Subject{ //this method loop on observers list and notify state changing @Override public void notifyListner(int extractedNumber) { for (Observer o : this.observers){ //observers' update method call o.update(extractedNumber); } } //simply generates a random number and call notifyListner public void extractNumber(){ Random randomGenerator = new Random(); int generated = randomGenerator.nextInt(100); System.out.println("Croupier: Generated number is: "+generated); notifyListner(generated); } }
package it.max.didato; /** * Interface for Observer objects */ public interface Observer { //method called on Subject notification public void update(int extractedNumber); }
package it.max.didato; //concrete class implements Observer public class ThreeChecker implements Observer { //method called by subject to notify state changing public void update(int extractedNumber) { if (extractedNumber % 3 == 0) exult(); } private void exult(){ System.out.println("Player: YEAH"); } }
This is main class to run example
package it.max.didato; public class Main { //main class that instantiates and registers Observer to Subject public static void main(String[] args) { Subject croupier = new NumberGenerator(); Observer player = new ThreeChecker(); //registering croupier.addListner(player); while(true){//infinite loop //casting to call extractNumber method NumberGenerator generator = (NumberGenerator)croupier; generator.extractNumber(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
