Design Principle
Strive for loosely coupled designs between objects that interact.
Loosely coupled designs allow us to build flexible OO systems that can handle change because they minimize the interdependency between objects.
Observer Pattern
The Subject contains the state and controls it. The observers use the state. There are many observers and they rely on the Subject to tell them when its state changes.
For the Subject to send notification
1) You first call a method(like setChanged()) to signify that the state has changed in your object.
2) Then, call notifyObservers() method (which calls observers update() method).
For the Observer to receive notifications
It implements the update method.
The class work flow:
1) Observers regist: Observers use Subject's registerObserver() method to regist
2) Subject send notification: Subject calls a method(like setChanged()) to signify that the state has changed in his object, then call notifyObservers() method (which calls observers update() method).
Example:
Subjct is the WeatherProvider, when the weather's temperature changed, it notices Observers who are a group of people who has buy its service(here we named these poeple are ClientA,ClientB)
WeatherProvider
public class WeatherProvider implements Subject {
private HashSet<Observer> observers;
private float temperature;
// -------------------------------------------------
public WeatherProvider() { // constructor
observers = new HashSet<Observer>();
}
// -------------------------------------------------
public void registObserver(Observer o) {
observers.add(o);
}
// -------------------------------------------------
public void removeObserver(Observer o) {
observers.remove(o);
}
// -------------------------------------------------
public void notifyObservers() {
for(Observer o: observers){
o.update(temperature);
}//end for
}
// -------------------------------------------------
public void temperatureChanged(){
notifyObservers();
} //end temperatureChanged()
// -------------------------------------------------
public void setTemperature(float temperature){
this.temperature=temperature;
temperatureChanged();
} //end setTemperature()
//other weather methods here
}
ClientA and ClientB
public class ClientA implements Observer {
private float temperature;
private Subject wetherProvider;
// -------------------------------------------------
public ClientA(Subject wetherProvider){
this.wetherProvider=wetherProvider;
wetherProvider.registObserver(this);
}
// -------------------------------------------------
public void update(float temperature) {
this.temperature = temperature;
display();
} // end update()
// -------------------------------------------------
// output the current temperature when you want to know it
public void display() {
System.out.println(ClientA.class.getSimpleName()+": current temperature is "+temperature);
} // end display()
}
public class ClientB implements Observer {
private float temperature;
private Subject wetherProvider;
// -------------------------------------------------
public ClientB(Subject wetherProvider){
this.wetherProvider=wetherProvider;
wetherProvider.registObserver(this);
}
// -------------------------------------------------
public void update(float temperature) {
this.temperature = temperature;
display();
} // end update()
// -------------------------------------------------
// output the current temperature when you want to know it
public void display() {
System.out.println(ClientA.class.getSimpleName()+": current temperature is "+temperature);
} // end display()
}
Test App
public class WeatherApp {
public static void main(String[] args) {
//subject
WeatherProvider WeatherProvider=new WeatherProvider();
//observers
Observer clientA=new ClientA(WeatherProvider);
Observer clientB=new ClientB(WeatherProvider);
//notify current temperature
WeatherProvider.setTemperature(80);
}//end main()
}
Run Result
Using Java's built-in Observer Pattern
Java has built-in support in several of its API. The most general is the Observer interface and the Observable class in the java.util an java.lang package. These are quite similar to our Subject and Observer interface.
With Java's built-in support, all you have to do is extend Observable and tell it when to notify the Observers. The API does the rest for you.
In either case, you need to call setChanged() for notifications to work.
clearChanged() sets the changed state back to false,
hasChaged() tells you the current state of the changed flag.
The above example is modified like this:
/* We don't need to keep track of our observers anymore,
or manage their registration and removal (the superclass will handle that),
so we're removed the code for register and notify.
*/
public class WeatherProvider extends Observable {
private float temperature;
// -------------------------------------------------
public WeatherProvider() { // constructor
// observers = new HashSet<Observer>();
}
// -------------------------------------------------
public void temperatureChanged(){
setChanged();
notifyObservers();
} //end temperatureChanged()
// -------------------------------------------------
public void setTemperature(float temperature){
this.temperature=temperature;
temperatureChanged();
} //end setTemperature()
public float getTemperature(){
return temperature;
}
//other weather methods here
}
public class ClientA implements java.util.Observer {
private float temperature;
private Observable observable;
// -------------------------------------------------
public ClientA(Observable observable){
this.observable=observable;
observable.addObserver(this);
}
// -------------------------------------------------
public void update(Observable o, Object arg) {
WeatherProvider weatherProvider=(WeatherProvider)o;
this.temperature=weatherProvider.getTemperature();
display();
}
// -------------------------------------------------
// output the current temperature when you want to know it
public void display() {
System.out.println(ClientA.class.getSimpleName()+": current temperature is "+temperature);
} // end display()
}
Applicaiton
Application of Observer Pattern