Studyon Minte9.com
Head First (Patterns)




Observer Pattern



* Use our own Observer and Subject:

	%java
		package testexample;
		import java.util.ArrayList;

		interface Subject {
		    public void registerObserver(Observer o);
		    public void removeObserver(Observer o);
		    public void notifyObservers();
		}
		interface Observer {
		    public void update(float temp);
		}
		interface DisplayElement {
		    public void display();
		}

		class MyData implements Subject {
		    
		    private ArrayList observers;
		    private float temperature;
		    
		    public MyData() {
			observers = new ArrayList();
		    }
		    
		    @Override
		    public void registerObserver(Observer o) {
			observers.add(o);
		    }
		    @Override
		    public void removeObserver(Observer o) {
			observers.remove(o);
		    }
		    @Override
		    public void notifyObservers() {
			for (int i=0; i<observers.size(); i++) {
			    Observer o = (Observer) observers.get(i);
			    o.update(temperature);
			}
		    }
		    
		    public void setTemperature(float t) {
			temperature = t;
			notifyObservers();
		    } 
		}

		class Web implements Observer, DisplayElement {
		    
		    private float temperature;
		    public Web (Subject s) {
			s.registerObserver(this); // Observer autoregister
		    }
		    @Override
		    public void update(float t) {
			temperature = t;
		    }
		    @Override
		    public void display() {
			System.out.println("WEB: " + temperature + " C");
		    }
		}


		class Mobile implements Observer, DisplayElement {
		    
		    private float temperature;
		    public Mobile (Subject s) {
			s.registerObserver(this); // Observer autoregister
		    }
		    @Override
		    public void update(float t) {
			temperature = t;
		    }
		    @Override
		    public void display() {
			System.out.println("MOBILE: " + temperature + " grade");
		    }
		}

		public class Testexample {
		    
		    public static void main(String[] args) {
			
			MyData myData = new MyData();
			Web web = new Web(myData);
			Mobile mobile = new Mobile(myData);
			
			/* --- Here is the important part --- */

			myData.setTemperature(10); // set property and notify observers
			web.display(); // Output: WEB: 10.0 C
			mobile.display(); // Output: MOBILE: 10.0 grade

		       // There is no need to write somenthing like:
		       // web.setTemperatura(10);
		       // mobile.setTemperatura(10);
                       // ....
		       // futureDisplay.setTemperature(10);

		    }
		}


* Use build Observer and Subject:
      
        Observable is not an interface, so you can't add Observable behavior to an existing class
        that already extends another superclass.
    
        The setChanged() method is meant to give you more flexibility. For example, if you don't want to notify
        observers every time, but only when temperature had changes more than half a degree.
 
	%java 
		package testexample;
		import java.util.Observable;
		import java.util.Observer;

		class MyData extends Observable {
		    
		    private float temperature;
		    
		    public void setTemperature(float t) {
			temperature = t;

			/* --- Look Here --- */
			
			setChanged(); // is mandatory to call this before notify
			notifyObservers(); // Automaticaly call update for every observer
		    } 
		    public float getTemperature() {
			return temperature;
		    }
		}
		class Mobile implements Observer {

		    private float temperature;
		    
		    public Mobile (Observable subject) {
			subject.addObserver(this); // Observer autoregister
		    }

		    /* --- Look Here --- */

		    @Override
		    public void update(Observable subject, Object arg) {
			if (subject instanceof MyData) {
			    MyData myData = (MyData) subject;
			    temperature = myData.getTemperature();
			}
		    }
		    public void display() {
			System.out.println("MOBILE: " + temperature);
		    }
		}
		public class Testexample {
		    public static void main(String[] args) {
			MyData myData = new MyData();
			Mobile mobile = new Mobile(myData);

			/* --- Look Here --- */

			myData.setTemperature(10);
			mobile.display(); // Observer display the new temperature
		    }
		}


* Swing ActionListener (Observer) example

	%java
		package testexample;
		import java.awt.BorderLayout;
		import javax.swing.*;
		import java.awt.event.*;

		public class Testexample extends JFrame{
		    public static void main(String[] args) {
			new Testexample().go();
		    }
		    
		    public void go() {

			JButton button = new JButton("Choose");
			button.addActionListener(new AngelListener()); // Subject add Observer
			
			getContentPane().add(BorderLayout.CENTER, button);
			
			setBounds(0, 0, 300, 300);
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			setVisible(true);
		    }
		    
		    class AngelListener implements ActionListener { // Observer
			@Override
			public void actionPerformed(ActionEvent e) { // update Observer
			    System.out.println("Don't do it, you might regret it!");
			}
		    }
		}


* Real life example

	%java

		public interface CardObserver {
		    void onCardChanged();
		}

		...

		public interface CardSubject {
		    
		    public void registerObserver(CardObserver o);
		    public void removeObserver(CardObserver o);
		    public void notifyObservers();
		}

		...

		public class Reset extends MenuItemAbstract implements CardObserver {
		    
			public Reset () { 
			    ...
			    
			    Card.getInstance().registerObserver(this);
			}

			public void onCardChanged() {
			    this.setEnabled(false);
			    if (Card.getInstance() instanceof CardQA) {
				this.setEnabled(true);
			    }
			}
		}

		...

		public class CardQA extends CardAbstract {
			
			...
			
			public void refresh() {
				...
				notifyObservers();
			}
		}