public class WeatherD extends Observable{ private double temperature; private double humidity; private double pressure; public double getTemperature() { return temperature; } public double getHumidity() { return humidity; } public double getPressure() { return pressure; } public void setMeasurements(double temp, double humidity, double pressure){ this.temperature = temp; this.humidity = humidity; this.pressure = pressure; double[] args = {temp,humidity,pressure};
//注释一 setChanged(); notifyObservers(args); } }
1.1.1 注释一:setChanged()方法将changed状态置为true,只有changed状态置为true时,在调用notifyObservers()时才会通知观察者。setChanged()方法让你在通知观察者时具有更多的弹性【在某些场景下,并不是发布者的数据每一次更新都要通知观察者】。
public void notifyObservers(Object arg) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ Object[] arrLocal; synchronized (this) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); }
1.1.2 可以调用clearChanged()将changed状态置为false,调用hasChanged()查看当前的changed的状态。
public class ObserverB implements Observer { private double temperature; private double humidity; private double pressure; @Override public void update(Observable o, Object arg) { //注释一
//1.push double[] args = (double[]) arg; this.temperature = args[0]; this.humidity = args[1]; this.pressure = args[2]; //2.pull WeatherD d = (WeatherD) o; this.temperature = d.getTemperature(); this.humidity = d.getHumidity(); this.pressure = d.getPressure(); printInfo(); } private void printInfo(){ StringBuilder info = new StringBuilder(); info.append("Current weather date is [temperature : ").append(this.temperature) .append(",humidity : ").append(this.humidity) .append(",pressure : ").append(this.pressure) .append("]."); System.out.println(info.toString()); } }
1.2.1 注释一:Java内置的观察者模式,提供了push(推)和pull(拉)的方式传递数据【push:发布者将所有的数据推送给观察者;pull:观察者通过调用发布者的Getter方法获取需要的数据】 。(通常认为,push的方式更正确)
需要注意的是,Observable是一个类,如果发布者同时还需要具备另一个超类的行为,就会陷入两难,毕竟Java不支持多继承,它限制了Observable的复用潜力(而增加复用潜力是模式的原动力)。
【遇到此类情况,你能做的就是自定义一套观察者模式】
2. 自定义观察者模式
自定义观察者模式必须具备四个角色:抽象发布者、具体发布者、抽象观察者、具体观察者。
2.1 抽象发布者
public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObersers(); }
2.2 具体发布者
通过接口实现发布者,避免了无法继承其它超类的局限。但是,也产生了一个新的问题,即:每创建一个观察者,都必须重写抽象观察者的方法。【当然,可以创建一个中间层,用来实现抽象发布者接口,同时继承其它超类。】
public class WeatherData implements Subject{ private double temperature; private double humidity; private double pressure; private List<Observer> observers; public WeatherData() { observers = new ArrayList<Observer>(); } public double getTemperature() { return temperature; } public double getHumidity() { return humidity; } public double getPressure() { return pressure; } public void setMeasurements(double temp, double humidity, double pressure){ this.temperature = temp; this.humidity = humidity; this.pressure = pressure; measurementsCharged(); } private void measurementsCharged(){ notifyObersers(); } @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { observers.remove(o); } @Override public void notifyObersers() { for (Observer observer : observers) { observer.update(temperature, humidity, pressure); } } }
2.3 抽象观察者
public interface Observer { public void update(double temp, double humidity, double pressure); }
2.4 具体观察者
public class ObserverA implements Observer { private double temperature; private double humidity; private double pressure; @Override public void update(double temp, double humidity, double pressure) { this.temperature = temp; this.humidity = humidity; this.pressure = pressure; printInfo(); } private void printInfo(){ StringBuilder info = new StringBuilder(); info.append("Current weather date is [temperature : ").append(this.temperature) .append(",humidity : ").append(this.humidity) .append(",pressure : ").append(this.pressure) .append("]."); System.out.println(info.toString()); } }
3. 参考资料
3.1 百度百科:《观察者模式》
3.2 O'Reilly:《Head First设计模式》