观测者模式定义了对象之间的一对多依赖,当一个对象状态发生改变时,其依赖者便会收到通知并做相应的更新。其原则是:为交互对象之间松耦合。以松耦合方式在一系列对象之间沟通状态,我们可以独立复用主题(Subject)/可观测者(Observable)和观测者(Observer),即只要遵守接口规则改变其中一方并不会影响到另一方。这也是其主要的设计原则。下面是一个简单的气象站发送天气信息给布告板,然后布告板把天气信息显示在板上的例子。
首先先建立三个接口,主题(Subject)、观测者(Observer)和显示内容(DisplayElement),分别代表气象站、布告板信息接收和布告板信息显示。
/** * 主题 */public interface Subject { // 观察者注册 public void registerObserver(Observer o); // 删除观察者 public void removeObserver(Observer o); // 当主题有内容更新时调用,用于通知观察者 public void notifyObserver();}
/** * 观察者 */public interface Observer { // 当气象站观测的天气发生变化时,主题会把参数值传给观察者 public void update(float temp);}
/** * 用于布告板显示 */public interface DisplayElement { // 在显示布告板上显示的操作 public void display();}
接下来是实现气象站()和布告板()了。
/** * 气象站实现主题,发布气象信息(气温) */public class WeatherStation implements Subject{ private ArrayList observers; private float temp; public WeatherStation() { // 加个ArrayList存放所有注册的Observer对象; observers = new ArrayList<>(); } @Override public void registerObserver(Observer o) { // 当新的观察者注册时添加进来 observers.add(o); } @Override public void removeObserver(Observer o) { // 当观察者取消注册时去除该观察者 int i = observers.indexOf(o); if (i>=0) { observers.remove(i); } } @Override public void notifyObserver() { // 更新状态,调用Observer的update告诉观察者有新的信息 for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer) observers.get(i); observer.update(temp); } } /* * 此方法用于气象站收到的数据,并且调用更新使数据实时通知给观察者 */ public void setMeasurements(float temp){ this.temp = temp; System.out.println("气象站测量的温度为:" + temp + "℃"); notifyObserver(); }}
/** * 布告板上的状态显示 */public class ConditionDisplay implements Observer,DisplayElement{ private float temp; private Subject weatherStation; public ConditionDisplay(Subject weatherStation) { // 构造时需要间主题/被观察者对象作为注册之用 this.weatherStation = weatherStation; weatherStation.registerObserver(this); } @Override public void display() { // 将数据显示在布告板上 System.out.println("布告板显示当前温度为:" + temp + "℃"); } @Override public void update(float temp) { // 接受来自主题/被观察者(气象站)的数据 this.temp = temp; display(); }}
测试结果
/** * 天气观测站 */public class WeatherObserver { public static void main(String[] args) { // 首先创建一个主题/被观察者 WeatherStation weatherStation = new WeatherStation(); // 创建观察者并将被观察者对象传入 ConditionDisplay conditionDisplay = new ConditionDisplay(weatherStation); // 设置气象站模拟收到的气温数据 weatherStation.setMeasurements(25); weatherStation.setMeasurements(24); weatherStation.setMeasurements(23); }}
JAVA内置观察者模式
可以使用java内置的观察者模式,这样就无需自己写Subject和Observer类了,在java.util包下继承的Observable和实现Observer类即可。其修改后的代码如下:
/** * 继承java内置的被观察者,因此不再需要注册和删除了 */public class WeatherStationN extends Observable{ private float temperature; public WeatherStationN() { // 由于继承了Observable,它已经创建了一个Vector来存放Observer对象的容器,所以此处不用再建立ArrayList } /* * 此方法用于气象站收到的数据,并且调用更新使数据实时通知给观察者 */ public void setMeasurements(float temp){ this.temperature = temp; System.out.println("气象站测量的温度为:" + temp + "℃"); // 更新强调用表示有状态更新 setChanged(); notifyObservers(temperature); }}
/** * 实现java内置Observer接口 */public class ConditionDisplayN implements java.util.Observer,DisplayElement{ private Observable observable; private float temp; public ConditionDisplayN(Observable observable) { // 构造器需要Observable作为参数 this.observable = observable; observable.addObserver(this); } @Override public void display() { // 将数据显示在布告板上 System.out.println("布告板显示当前温度为:" + temp + "℃"); } @Override public void update(Observable o, Object arg) { // 当被观察者有更新使触发 if (o instanceof WeatherStationN) { this.temp = (float) arg; display(); } }}
测试运行结果
/** * 天气观测站 */public class WeatherObserver { public static void main(String[] args) { // 首先创建一个主题/被观察者 WeatherStationN weatherStationN = new WeatherStationN(); // 创建观察者并将被观察者对象传入 ConditionDisplayN conditionDisplayN = new ConditionDisplayN(weatherStationN); // 设置气象站模拟收到的气温数据 weatherStationN.setMeasurements(30); weatherStationN.setMeasurements(25); weatherStationN.setMeasurements(20); }}
联系客服