HeadFirst设计模式之观察者模式
一、什么是观察者模式
观察者模式定义了一系列对象间一对多的关系,当主题对象的状态发生变化时,会通知所有观察者
二、自定义观察模式
1.
2.
1 package headfirst.designpatterns.observer.weather; 2 3 public interface Subject { 4 public void registerObserver(Observer o); 5 public void removeObserver(Observer o); 6 public void notifyObservers(); 7 }
3.
1 package headfirst.designpatterns.observer.weather; 2 3 public interface Observer { 4 public void update(float temp, float humidity, float pressure); 5 }
4.
1 package headfirst.designpatterns.observer.weather; 2 3 import java.util.*; 4 5 public class WeatherData implements Subject { 6 private ArrayList<Observer> observers; 7 private float temperature; 8 private float humidity; 9 private float pressure; 10 11 public WeatherData() { 12 observers = new ArrayList<Observer>(); 13 } 14 15 public void registerObserver(Observer o) { 16 observers.add(o); 17 } 18 19 public void removeObserver(Observer o) { 20 int i = observers.indexOf(o); 21 if (i >= 0) { 22 observers.remove(i); 23 } 24 } 25 26 public void notifyObservers() { 27 for (Observer observer : observers) { 28 observer.update(temperature, humidity, pressure); 29 } 30 } 31 32 public void measurementsChanged() { 33 notifyObservers(); 34 } 35 36 public void setMeasurements(float temperature, float humidity, float pressure) { 37 this.temperature = temperature; 38 this.humidity = humidity; 39 this.pressure = pressure; 40 measurementsChanged(); 41 } 42 43 public float getTemperature() { 44 return temperature; 45 } 46 47 public float getHumidity() { 48 return humidity; 49 } 50 51 public float getPressure() { 52 return pressure; 53 } 54 55 }
5.
1 package headfirst.designpatterns.observer.weather; 2 3 public class StatisticsDisplay implements Observer, DisplayElement { 4 private float maxTemp = 0.0f; 5 private float minTemp = 200; 6 private float tempSum= 0.0f; 7 private int numReadings; 8 private WeatherData weatherData; 9 10 public StatisticsDisplay(WeatherData weatherData) { 11 this.weatherData = weatherData; 12 weatherData.registerObserver(this); 13 } 14 15 public void update(float temp, float humidity, float pressure) { 16 tempSum += temp; 17 numReadings++; 18 19 if (temp > maxTemp) { 20 maxTemp = temp; 21 } 22 23 if (temp < minTemp) { 24 minTemp = temp; 25 } 26 27 display(); 28 } 29 30 public void display() { 31 System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) 32 + "/" + maxTemp + "/" + minTemp); 33 } 34 }
6.
package headfirst.designpatterns.observer.weather; public interface DisplayElement { public void display(); }
7.
1 package headfirst.designpatterns.observer.weather; 2 3 public class CurrentConditionsDisplay implements Observer, DisplayElement { 4 private float temperature; 5 private float humidity; 6 private Subject weatherData; 7 8 public CurrentConditionsDisplay(Subject weatherData) { 9 this.weatherData = weatherData; 10 weatherData.registerObserver(this); 11 } 12 13 public void update(float temperature, float humidity, float pressure) { 14 this.temperature = temperature; 15 this.humidity = humidity; 16 display(); 17 } 18 19 public void display() { 20 System.out.println("Current conditions: " + temperature 21 + "F degrees and " + humidity + "% humidity"); 22 } 23 }
8.
1 package headfirst.designpatterns.observer.weather; 2 3 public class HeatIndexDisplay implements Observer, DisplayElement { 4 float heatIndex = 0.0f; 5 private WeatherData weatherData; 6 7 public HeatIndexDisplay(WeatherData weatherData) { 8 this.weatherData = weatherData; 9 weatherData.registerObserver(this); 10 } 11 12 public void update(float t, float rh, float pressure) { 13 heatIndex = computeHeatIndex(t, rh); 14 display(); 15 } 16 17 private float computeHeatIndex(float t, float rh) { 18 float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) 19 + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) 20 + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) + 21 (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * 22 (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) + 23 (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) + 24 0.000000000843296 * (t * t * rh * rh * rh)) - 25 (0.0000000000481975 * (t * t * t * rh * rh * rh))); 26 return index; 27 } 28 29 public void display() { 30 System.out.println("Heat index is " + heatIndex); 31 } 32 }
9.
1 package headfirst.designpatterns.observer.weather; 2 3 public class WeatherStation { 4 5 public static void main(String[] args) { 6 WeatherData weatherData = new WeatherData(); 7 8 CurrentConditionsDisplay currentDisplay = 9 new CurrentConditionsDisplay(weatherData); 10 StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); 11 ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); 12 13 weatherData.setMeasurements(80, 65, 30.4f); 14 weatherData.setMeasurements(82, 70, 29.2f); 15 weatherData.setMeasurements(78, 90, 29.2f); 16 } 17 }
10.
1 package headfirst.designpatterns.observer.weather; 2 3 public class WeatherStationHeatIndex { 4 5 public static void main(String[] args) { 6 WeatherData weatherData = new WeatherData(); 7 CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); 8 StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); 9 ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); 10 HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); 11 12 weatherData.setMeasurements(80, 65, 30.4f); 13 weatherData.setMeasurements(82, 70, 29.2f); 14 weatherData.setMeasurements(78, 90, 29.2f); 15 } 16 }
三、Java.util.Observable
1.
1 package headfirst.designpatterns.observer.weatherobservable; 2 3 public interface DisplayElement { 4 public void display(); 5 }
2.
1 package headfirst.designpatterns.observer.weatherobservable; 2 3 import java.util.Observable; 4 5 public class WeatherData extends Observable { 6 private float temperature; 7 private float humidity; 8 private float pressure; 9 10 public WeatherData() { } 11 12 public void measurementsChanged() { 13 setChanged(); 14 notifyObservers(); 15 } 16 17 public void setMeasurements(float temperature, float humidity, float pressure) { 18 this.temperature = temperature; 19 this.humidity = humidity; 20 this.pressure = pressure; 21 measurementsChanged(); 22 } 23 24 public float getTemperature() { 25 return temperature; 26 } 27 28 public float getHumidity() { 29 return humidity; 30 } 31 32 public float getPressure() { 33 return pressure; 34 } 35 }
3.
1 package headfirst.designpatterns.observer.weatherobservable; 2 3 import java.util.Observable; 4 import java.util.Observer; 5 6 public class StatisticsDisplay implements Observer, DisplayElement { 7 private float maxTemp = 0.0f; 8 private float minTemp = 200; 9 private float tempSum= 0.0f; 10 private int numReadings; 11 12 public StatisticsDisplay(Observable observable) { 13 observable.addObserver(this); 14 } 15 16 public void update(Observable observable, Object arg) { 17 if (observable instanceof WeatherData) { 18 WeatherData weatherData = (WeatherData)observable; 19 float temp = weatherData.getTemperature(); 20 tempSum += temp; 21 numReadings++; 22 23 if (temp > maxTemp) { 24 maxTemp = temp; 25 } 26 27 if (temp < minTemp) { 28 minTemp = temp; 29 } 30 31 display(); 32 } 33 } 34 35 public void display() { 36 System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) 37 + "/" + maxTemp + "/" + minTemp); 38 } 39 }
4.
1 package headfirst.designpatterns.observer.weatherobservable; 2 3 import java.util.Observable; 4 import java.util.Observer; 5 6 public class HeatIndexDisplay implements Observer, DisplayElement { 7 float heatIndex = 0.0f; 8 9 public HeatIndexDisplay(Observable observable) { 10 observable.addObserver(this); 11 } 12 13 public void update(Observable observable, Object arg) { 14 if (observable instanceof WeatherData) { 15 WeatherData weatherData = (WeatherData)observable; 16 float t = weatherData.getTemperature(); 17 float rh = weatherData.getHumidity(); 18 heatIndex = (float) 19 ( 20 (16.923 + (0.185212 * t)) + 21 (5.37941 * rh) - 22 (0.100254 * t * rh) + 23 (0.00941695 * (t * t)) + 24 (0.00728898 * (rh * rh)) + 25 (0.000345372 * (t * t * rh)) - 26 (0.000814971 * (t * rh * rh)) + 27 (0.0000102102 * (t * t * rh * rh)) - 28 (0.000038646 * (t * t * t)) + 29 (0.0000291583 * (rh * rh * rh)) + 30 (0.00000142721 * (t * t * t * rh)) + 31 (0.000000197483 * (t * rh * rh * rh)) - 32 (0.0000000218429 * (t * t * t * rh * rh)) + 33 (0.000000000843296 * (t * t * rh * rh * rh)) - 34 (0.0000000000481975 * (t * t * t * rh * rh * rh))); 35 display(); 36 } 37 } 38 39 public void display() { 40 System.out.println("Heat index is " + heatIndex); 41 } 42 }
5.
1 package headfirst.designpatterns.observer.weatherobservable; 2 3 import java.util.Observable; 4 import java.util.Observer; 5 6 public class ForecastDisplay implements Observer, DisplayElement { 7 private float currentPressure = 29.92f; 8 private float lastPressure; 9 10 public ForecastDisplay(Observable observable) { 11 observable.addObserver(this); 12 } 13 14 public void update(Observable observable, Object arg) { 15 if (observable instanceof WeatherData) { 16 WeatherData weatherData = (WeatherData)observable; 17 lastPressure = currentPressure; 18 currentPressure = weatherData.getPressure(); 19 display(); 20 } 21 } 22 23 public void display() { 24 System.out.print("Forecast: "); 25 if (currentPressure > lastPressure) { 26 System.out.println("Improving weather on the way!"); 27 } else if (currentPressure == lastPressure) { 28 System.out.println("More of the same"); 29 } else if (currentPressure < lastPressure) { 30 System.out.println("Watch out for cooler, rainy weather"); 31 } 32 } 33 }
6.
1 package headfirst.designpatterns.observer.weatherobservable; 2 3 public class WeatherStation { 4 5 public static void main(String[] args) { 6 WeatherData weatherData = new WeatherData(); 7 8 CurrentConditionsDisplay currentConditions = new CurrentConditionsDisplay(weatherData); 9 StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); 10 ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); 11 12 weatherData.setMeasurements(80, 65, 30.4f); 13 weatherData.setMeasurements(82, 70, 29.2f); 14 weatherData.setMeasurements(78, 90, 29.2f); 15 } 16 }
四、Swing中的观察者模式
1.
1 package headfirst.observer.swing; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 import javax.swing.event.*; 7 8 public class SwingObserverExample { 9 JFrame frame; 10 11 public static void main(String[] args) { 12 SwingObserverExample example = new SwingObserverExample(); 13 example.go(); 14 } 15 16 public void go() { 17 frame = new JFrame(); 18 19 JButton button = new JButton("Should I do it?"); 20 button.addActionListener(new AngelListener()); 21 button.addActionListener(new DevilListener()); 22 frame.getContentPane().add(BorderLayout.CENTER, button); 23 24 // Set frame properties 25 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 26 frame.getContentPane().add(BorderLayout.CENTER, button); 27 frame.setSize(300,300); 28 frame.setVisible(true); 29 } 30 31 class AngelListener implements ActionListener { 32 public void actionPerformed(ActionEvent event) { 33 System.out.println("Don't do it, you might regret it!"); 34 } 35 } 36 37 class DevilListener implements ActionListener { 38 public void actionPerformed(ActionEvent event) { 39 System.out.println("Come on, do it!"); 40 } 41 } 42 }
You can do anything you set your mind to, man!