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()方法讓你在通知觀察者時具備更多的彈性【在某些場景下,並非發佈者的數據每一次更新都要通知觀察者】。java
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的方式更正確)app
須要注意的是,Observable是一個類,若是發佈者同時還須要具有另外一個超類的行爲,就會陷入兩難,畢竟Java不支持多繼承,它限制了Observable的複用潛力(而增長複用潛力是模式的原動力)。
ide
【遇到此類狀況,你能作的就是自定義一套觀察者模式】ui
2. 自定義觀察者模式this
自定義觀察者模式必須具有四個角色:抽象發佈者、具體發佈者、抽象觀察者、具體觀察者。spa
2.1 抽象發佈者設計
public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObersers(); }
2.2 具體發佈者code
經過接口實現發佈者,避免了沒法繼承其它超類的侷限。可是,也產生了一個新的問題,即:每建立一個觀察者,都必須重寫抽象觀察者的方法。【固然,能夠建立一箇中間層,用來實現抽象發佈者接口,同時繼承其它超類。】server
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設計模式》