设计模式——观察者模式
观察者模式面向的需求是:
A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B变化的一瞬间做出反应。
举个例子,新闻里喜闻乐见的警察抓小偷,警察需要在小偷伸手作案的时候实施抓捕。在这个例子里,警察是观察者、小偷是被观察者,警察需要时刻盯着小偷的一举一动,才能保证不会错过任何瞬间。程序里的观察者和这种真正的【观察】略有不同,观察者不需要时刻盯着被观察者(例如A不需要每隔1ms就检查一次B的状态),二是采用注册(Register)或者成为订阅(Subscribe)的方式告诉被观察者:我需要你的某某状态,你要在它变化时通知我。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。
下面的例子是天气更新的观察者模式的实际应用,当天气更新后会通知当前天气的类(CurrentConditionsDisplay)和预测天气的类(ForecastDisplay)。
如果不用观察者模式去实现,观察者可能需要不断的查询 天气类中天气是否变化(比如每秒查询一次)。
观察者接口:
/** * 观察者 */ public interface Observer { void update(); }
被观察者接口:
/** * 发布者、被观察者 */ public interface Subject { /** * 注册观察者 */ void registerObserver(Observer observer); /** * 移除观察者 */ void removeObserver(Observer observer); /** * 通知观察者 */ void notifyObservers(); }
用于显示观察者信息的接口,继承观察者的类同时需要继承该类(也可以写在Observer类中):
/** * 用于显示观察者信息变化 */ public interface DisplayElement { void display(); }
天气的类(被观察者),当天气数据发生变化时,会通知所有的观察者更新数据:
public class WeatherData implements Subject { private List<Observer> observers; private float temperature;//温度 private float humidity;//湿度 private float pressure;//气压 private List<Float> forecastTemperatures;//未来几天的温度 public WeatherData() { this.observers = new ArrayList<Observer>(); } @Override public void registerObserver(Observer observer) { this.observers.add(observer); } @Override public void removeObserver(Observer observer) { this.observers.remove(observer); } @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(); } } public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure, List<Float> forecastTemperatures) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; this.forecastTemperatures = forecastTemperatures; measurementsChanged(); } public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } public List<Float> getForecastTemperatures() { return forecastTemperatures; } }
当前天气的类(CurrentConditionsDisplay),该类为天气的观察者。
public class CurrentConditionsDisplay implements Observer, DisplayElement { private WeatherData weatherData; private float temperature;//温度 private float humidity;//湿度 private float pressure;//气压 public CurrentConditionsDisplay(WeatherData weatherData) { this.weatherData = weatherData; this.weatherData.registerObserver(this); } @Override public void display() { System.out.println("当前温度为:" + this.temperature + "℃"); System.out.println("当前湿度为:" + this.humidity); System.out.println("当前气压为:" + this.pressure); } @Override public void update() { this.temperature = this.weatherData.getTemperature(); this.humidity = this.weatherData.getHumidity(); this.pressure = this.weatherData.getPressure(); display(); } }
预测天气的类(ForecastDisplay),该类为天气的观察者。
public class ForecastDisplay implements Observer, DisplayElement { private WeatherData weatherData; private List<Float> forecastTemperatures;//未来几天的温度 public ForecastDisplay(WeatherData weatherData) { this.weatherData = weatherData; this.weatherData.registerObserver(this); } @Override public void display() { System.out.println("未来几天的气温"); int count = forecastTemperatures.size(); for (int i = 0; i < count; i++) { System.out.println("第" + i + "天:" + forecastTemperatures.get(i) + "℃"); } } @Override public void update() { this.forecastTemperatures = this.weatherData.getForecastTemperatures(); display(); } }
以上类的结构关系如下:
主程序入口:
@OnClick(R.id.notifiyObservers) public void onNotifiyObservers(){ List<Float> futureTemperature = new ArrayList<>(); futureTemperature.add(2.0f); futureTemperature.add(3.0f); //构造 被观察者 WeatherData weatherData = new WeatherData(); //构造 观察者1,初始话的时候将自身添加到被观察者的对队列中 ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); //构造 观察者1,初始话的时候将自身添加到被观察者的对队列中 CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData); // 被观察者 天气数据发生变化,内部会调用 队列中的观察者update函数 weatherData.setMeasurements(1,20,200,futureTemperature); }
运行的结果如下:
梦想不是浮躁,而是沉淀和积累