观察者模式
观察者模式 = 出版者(主题) + 订阅者(观察者)
1、主题对象管理某些数据
2、当主题内的数据改变就会通知观察者
3、观察者已经订阅(注册)主题以便在主题数据改变时能够收到更新
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖都会收到通知并自动更新。
设计原则:
1、为了交互对象之间的松耦合设计努力。松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,时因为对象之间的互相依赖降到了最低。
案例代码:
/** * 主题接口 * * @author guoxin */ public interface Subject { /** * 注册观察者 * * @param o 观察者接口 */ void registerObserver(Observer o); /** * 注销观察者 * * @param o 观察者接口 */ void removeObserver(Observer o); /** * 当主题状态改变时,这个方法会被调用,以通知所有的观察者 */ void notifyObserver(); }
/** * 观察者接口 * * @author guoxin */ public interface Observer { /** * 跟新数据 * * @param temp 温度 * @param humidity 湿度 * @param pressure 压力 */ void update(float temp, float humidity, float pressure); }
/** * 数据显示接口 * * @author guoxin */ public interface DisplayElement { void display(); }
import java.util.ArrayList; import java.util.List; /** * 气象数据类 * * @author guoxin */ public class WeatherData implements Subject { private List<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<>(); } /** * 注册观察者 * * @param o 观察者接口 */ @Override public void registerObserver(Observer o) { observers.add(o); } /** * 注销观察者 * * @param o 观察者接口 */ @Override public void removeObserver(Observer o) { if (observers.contains(o)) { observers.remove(o); } } /** * 通知观察者 */ @Override public void notifyObserver() { for (Observer o : observers) { o.update(temperature, humidity, pressure); } } /** * 当从气象站得到更新观测值时,我们通知观察者 */ public void measurementsChanged() { notifyObserver(); } /** * 设置数据 * * @param temperature 温度 * @param humidity 湿度 * @param pressure 压力 */ public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
/** * 当前气象面板 * * @author guoxin */ public class CurrentConditionDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject subject; public CurrentConditionDisplay(Subject subject) { this.subject = subject; subject.registerObserver(this); } @Override public void display() { System.out.println("current conditions: " + temperature + "F degree and " + humidity + "% humidity"); } /** * 当update()被调用时,我们把温度和湿度保存起来,然后调用display()。 * * @param temp 温度 * @param humidity 湿度 * @param pressure 压力 */ @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } }
/** * 酷热面板 * * @author guoxin */ public class HeatIndexDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject subject; public HeatIndexDisplay(Subject subject) { this.subject = subject; subject.registerObserver(this); } @Override public void display() { float heat = computeHeatIndex(temperature, humidity); System.out.println("health index is " + heat); } /** * 当update()被调用时,我们把温度和湿度保存起来,然后调用display()。 * * @param temp 温度 * @param humidity 湿度 * @param pressure 压力 */ @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } /** * 计算酷热指数 * * @param t 温度 * @param rh 湿度 * @return 酷热指数 */ private float computeHeatIndex(float t, float rh) { return (float) ((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) + (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) + (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) + 0.000000000843296 * (t * t * rh * rh * rh)) - (0.0000000000481975 * (t * t * t * rh * rh * rh))); } }
/** * 测试类 * * @author guoxin */ public class WeatherStation { public static void main(String[] args) { WeatherData wd = new WeatherData(); CurrentConditionDisplay ccd = new CurrentConditionDisplay(wd); HeatIndexDisplay hid = new HeatIndexDisplay(wd); wd.setMeasurements(80, 65, 30.4f); wd.setMeasurements(82, 70, 29.2f); } }
类图: