330 likes | 525 Views
观察者模式. 观察者模式. 气象监控应用系统概观 系统有三个部分: 气象站 — 获取实际气象数据的物理设备 气象数据对象 — 跟踪气象站的数据,并更新布告板 布告板 — 向用户显示当前的目前状况 ( 温度、湿度、气压 ) 或气象统计或天气预报. Weather 对象知道如何跟物理气象站联系,取得新的数据。我们的工作是建立一个应用, 利用 Weather 对象的数据 , 更新三个布告板 。. 有三个布告板,将来可能需要增加新的布告板。. 气象站送来的数据类 (WeatherData). 我们的工作是实现 measurementsChanged() ,
E N D
观察者模式 气象监控应用系统概观 系统有三个部分: 气象站— 获取实际气象数据的物理设备 气象数据对象— 跟踪气象站的数据,并更新布告板 布告板 — 向用户显示当前的目前状况(温度、湿度、气压)或气象统计或天气预报
Weather对象知道如何跟物理气象站联系,取得新的数据。我们的工作是建立一个应用,利用Weather对象的数据,更新三个布告板。Weather对象知道如何跟物理气象站联系,取得新的数据。我们的工作是建立一个应用,利用Weather对象的数据,更新三个布告板。
有三个布告板,将来可能需要增加新的布告板。有三个布告板,将来可能需要增加新的布告板。
气象站送来的数据类(WeatherData) 我们的工作是实现 measurementsChanged(), 好让它更新目前状况、 气象统计和天气预报的 显示布告板。 不在乎此方法是如何调用的,只在乎它被调用了。
一个可能的实现 public class WeatherData { // 实例变量声明 public void measurementsChanged() { float temp = getTemperature(); float humidity = getHumidity(); float pressure = getPressure(); currentConditionsDisplay.update(temp, humidity, pressure); statisticsDisplay.update(temp, humidity, pressure); forecastDisplay.update(temp, humidity, pressure); } // 其它WeatherData方法 } 传入最新的测量值,调用布告板的更新显 示。 取得最近的测量值。 更新布告板。
我们的实现的缺陷在哪里? 针对具体的实现编码。如果不修改程序,我们就无法 增加或删除其它显示成分。 … currentConditionsDisplay.update(temp, humidity, pressure); statisticsDisplay.update(temp, humidity, pressure); forecastDisplay.update(temp, humidity, pressure); … 针对具体实现编程,导致增加或删除布告板时,必须修改程序。
观察者模式也称为发布-订阅模式 • 报社的业务就是出版报纸 • 向某家报社订阅报纸,只要他们有新报纸出版,就会给 • 你送来。只要你是他们的用户,你就会一直收到新报纸 • 当你不想再看报纸的时候,取消订阅,他们就不会再送 • 新报纸 • 只要报社还在运营,就会一直有人(或单位)向他们订 • 阅报纸或取消订阅报纸
观察者模式类图 实现观察者模式的一种方法。
松耦合的威力 当两个对象是松耦合的,它们彼此之间能够交互,但是 相互了解很少。 观察者模式提供了主题和观察者之间的松耦合设计。 因为主题只知道观察者实现了某个接口(即Observer接口), 主题不需要知道具体观察者是谁、作了些什么或其它任何 细节。要增加新的观察者或删除观察者,主题不会受到任 何影响,不必修改主题代码。 可以独立地复用主题和观察者,它们之间互不影响, 即是松耦合的。
松耦合的威力(续) 由于松耦合设计使得对象间的依赖最小化,所以, 我们能够创建柔性的OO系统,应对变化的情况,因为 对象之间的依赖降到了最低。
设计气象站 右边三个布告板也应该有一个“主题”指针指向WeatherData对象,本图未画出来。
实现气象站 public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } public interface Observer { public void update(float temp, float humidity, float pressure); } public interface DisplayElement { public void display(); } 需要观察者作为参数。
实现气象数据的Subject接口 public class WeatherData implements Subject { private ArrayList observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList(); } ArrayList记录观察者。
public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } }
public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } // other WeatherData methods here }
实现显示 public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } weatherData供注册或取消注册之用。 另外两个布告板的实现非常类似。
为气象站提供动力 public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } 模拟新的气象测量。
Java内置的观察者模式 • java.util包(package)内包含了最基本的Observable类与 • Observer接口,这与我们subject接口和Observer接口很 • 相似。 • Java GUI。例如,JButton可以增加或删除倾听者 • (listener),例如,ActionListener能倾听在按钮上发生的 • 动作。这些倾听者就是观察者。 • JavaBeans。
实例代码分析 public class Secretary { //前台秘书类 private ArrayList observers; // 同事列表 private string action; public Secretary () { observers = new ArrayList(); } public void attach(StockObserver observer) // 增加 { observers.add(observer) } public void notify() { // 通知 for (int i=0; i<observers.size(); i++) { StockObserver observer = (StockObserver) observers.get(i) observer. update(); } } public void secretaryAction(string action) { // 发生新的事件 this.action = action; notify( ); } … }
public class StockObserver // 看股票同事类 { private string name; private Secretary sub; public StockObserver(string name, Secretary sub) { this.name = name; this.sub = sub; sub.attach(name); } public void update( ) { System.out.println(“关闭股票,继续工作!"); } … } public class client { //客户端程序 public static void main(String[] args) { // 前台小姐 Secretary qiantai = new Secretary ( ); // 看股票同事 StockObserver tongshi1 = new StockObserver(“张山”); StockObserver tongshi2 = new StockObserver(“李四”); // 发现老板回来 qiantai.secretaryAction(“老板回来了”); } }