- 浏览: 1829364 次
文章分类
最新评论
-
coosummer:
推荐使用http://buttoncssgenerator.c ...
CSS控制<a>标签变为button -
Allen_J_Will:
哥们,事情没有你说的那么简单,很大的一个项目中,依赖jar包的 ...
struts中java.lang.NoClassDefFoundError: com/opensymphony/xwork2/util/TextUtils的解决办法
设计模式学习--观察者模式(Observer Pattern)
设计模式学习--观察者模式(Oberser Pattern)
2013年5月18日 天气:热!
下午15:28 设计模式学习中
学习者:小巫
什么是观察者模式?
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
怎么设计一个观察者模式的程序?
确定两个对象:1. 主题
2.观察者
确定这两个对象之间的关系:
主题对象管理某些数据,一旦数据发生改变,会主动向观察者进行通知,然而观察者不必向主题进行索取。
主题并不知道具体的观察者是谁,这是它们之间的关系。
以上涉及到的设计原则:
为了交互对象之间的松耦合设计而努力
具体实例:气象站的实现
1. 定义一个主题接口Subject
package observerPattern; /** * 主题接口 * @author wwj * */ public interface Subject { public void registerObserver(Observer o); //这两个方法都需要一个观察者作为变量,该观察者是用那个来注册和删除的 public void removeObserver(Observer o); public void notifyObserver(); //当主题状态发生改变时,这个方法会被调用,以通知所有的观察者 }
2. 定义一个观察者接口Observer
package observerPattern; /** * 观察者接口 * @author wwj * */ public interface Observer { public void update(float temp, float humidity, float pressure); }
3. 定义一般气象布告板接口DisplayElement
package observerPattern; /** * 公告板接口 * @author wwj * */ public interface DisplayElement { public void display(); }
4. 定义主题类:WeatherData实现接口
package observerPattern; import java.util.ArrayList; /** * WeatherData实现了Subject接口 * @author wwj * */ public class WeatherData implements Subject { private ArrayList observers; //用于记录观察者 private float temperature; //温度 private float humidity; //湿度 private float pressure; //压力 public WeatherData() { 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() { for(int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObserver(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
5. 定义四个布告板类实现观察者接口和布告板接口
package observerPattern; /** * 观察者类实现观察者接口和显示板接口 * @author wwj * */ public class CurrentConditionDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weathderData; public CurrentConditionDisplay(Subject weathderData) { this.weathderData = weathderData; weathderData.registerObserver(this); //注册 } @Override public void display() { System.out.println("Current coditions: " + temperature + "F degress and " + humidity + "% humidity"); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } }
package observerPattern; /** * 天气统计布告板 * @author wwj * */ public class StatisticsDisplay implements Observer, DisplayElement { private float maxTemp = 0.0f;; //最大温度 private float minTemp = 200; //最小温度 private float tempSum = 0.0f; //统计温度和 private int numReadings; //统计温度次数 private WeatherData weatherData; public StatisticsDisplay(WeatherData weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp); } @Override public void update(float temp, float humidity, float pressure) { tempSum += temp; numReadings++; if(temp > maxTemp) { maxTemp = temp; } if(temp < minTemp) { minTemp = temp; } display(); } }
package observerPattern; /** * 天气预报布告板 * @author wwj * */ public class ForecastDisplay implements Observer, DisplayElement { private float currentPressure = 29.92f; //当前气压 private float lastPressure; //以往气压 private WeatherData weatherData; public ForecastDisplay(WeatherData weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("Forcast:"); if(currentPressure > lastPressure) { System.out.println("Improving weather on the way!"); } else if(currentPressure == lastPressure) { System.out.println("more of the same"); } else if(currentPressure < lastPressure) { System.out.println("Watch out for cooler, rainy weather"); } } @Override public void update(float temp, float humidity, float pressure) { lastPressure = currentPressure; currentPressure = pressure; display(); } }
package observerPattern; /** * 酷热指数布告板 * * @author wwj * 注:那个计算酷热指数的公式不必深究 */ public class HeatIndexDisplay implements Observer, DisplayElement { float heatIndex = 0.0f; private WeatherData weatherData; public HeatIndexDisplay(WeatherData weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float t, float rh, float pressure) { heatIndex = computeHeatIndex(t, rh); display(); } private float computeHeatIndex(float t, float rh) { float index = (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))); return index; } public void display() { System.out.println("Heat index is " + heatIndex); } }
6. 来吧,开始测试
package observerPattern; /** * 测试类 * @author wwj * */ public class WeatherStation { public static void main(String[] args) { //建立一个WeatherData对象 WeatherData weatherData = new WeatherData(); //第一个布告板 CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay( weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); // 模拟新的气象数据 weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } }
7. 测试结果:
Current coditions: 80.0F degress and 65.0% humidity Avg/Max/Min temperature = 80.0/80.0/80.0 Forcast: Improving weather on the way! Heat index is 82.95535 Current coditions: 82.0F degress and 70.0% humidity Avg/Max/Min temperature = 81.0/82.0/80.0 Forcast: Watch out for cooler, rainy weather Heat index is 86.90124 Current coditions: 78.0F degress and 90.0% humidity Avg/Max/Min temperature = 80.0/82.0/78.0 Forcast: more of the same Heat index is 83.64967
以上的观察者模式实现是通过主题以“推”的方式通知观察者们,观察者可以在一次通知中一口气得到所有东西。
因为观察者与主题发生了争吵,观察者有自己的想法,希望能“拉”走主题的状态,然而Java内置的Observer模式就支持这样,下面来看看吧。
1. 继承Observable类的WeatherData(不再需要自定义接口了,但这样真的好吗?)
package weatherObservable; import java.util.Observable; /** * 使用Java内置的观察者模式 * @author wwj * */ public class WeatherData extends Observable { private float temperature; private float humidity; private float pressure; /** * 我们的构造器不再需要为了记住观察者们而建立数据结构了 */ public WeatherData(){} public void measurementsChanged() { setChanged(); //Observable类方法 notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } }
2. 4个布告板中的代码稍微发生了点变化
package weatherObservable; import java.util.Observable; import java.util.Observer; /** * 实现Java内置的观察者接口,布告板不变 * @author wwj * */ public class CurrentConditionDisplay implements Observer, DisplayElement{ Observable observable; private float temperature; private float humidity; public CurrentConditionDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); //登记为观察者 } @Override public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } /** * 在这个方法当中,先确定可观察者属于WeatherData类型,然后利用getter方法获取温度和温度测量值,最后调用display(); */ @Override public void update(Observable obs, Object arg) { if(obs instanceof WeatherData) { WeatherData weatherData = (WeatherData) obs; this.temperature = weatherData.getTemperature(); this.humidity = weatherData.getHumidity(); display(); } } }
package weatherObservable; import java.util.Observable; import java.util.Observer; /** * 天气预报布告板 * @author wwj * */ public class ForecastDisplay implements Observer, DisplayElement { private Observable observable; private float currentPressure = 29.92f; //当前气压 private float lastPressure; //以往气压 public ForecastDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); } @Override public void display() { System.out.println("Forcast:"); if(currentPressure > lastPressure) { System.out.println("Improving weather on the way!"); } else if(currentPressure == lastPressure) { System.out.println("more of the same"); } else if(currentPressure < lastPressure) { System.out.println("Watch out for cooler, rainy weather"); } } @Override public void update(Observable o, Object arg) { if (o instanceof WeatherData) { WeatherData weatherData = (WeatherData)observable; lastPressure = currentPressure; currentPressure = weatherData.getPressure(); display(); } } }
package weatherObservable; import java.util.Observable; import java.util.Observer; /** * 天气统计布告板 * @author wwj * */ public class StatisticsDisplay implements Observer, DisplayElement { private float maxTemp = 0.0f;; //最大温度 private float minTemp = 200; //最小温度 private float tempSum = 0.0f; //统计温度和 private int numReadings; //统计温度次数 private Observable observable; public StatisticsDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); } @Override public void display() { System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp); } @Override public void update(Observable obs, Object arg) { if(obs instanceof WeatherData) { WeatherData weatherData = (WeatherData)obs; float temp = weatherData.getTemperature(); tempSum += temp; numReadings++; if (temp > maxTemp) { maxTemp = temp; } if (temp < minTemp) { minTemp = temp; } display(); } } }
package weatherObservable; import java.util.Observable; import java.util.Observer; /** * 酷热指数布告板 * * @author wwj * 注:那个计算酷热指数的公式不必深究 */ public class HeatIndexDisplay implements Observer, DisplayElement { float heatIndex = 0.0f; private WeatherData weatherData; private Observable observable; public HeatIndexDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); } private float computeHeatIndex(float t, float rh) { float index = (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))); return index; } public void display() { System.out.println("Heat index is " + heatIndex); } @Override public void update(Observable obs, Object arg) { if(obs instanceof WeatherData) { WeatherData weatherData = (WeatherData)observable; float t = weatherData.getTemperature(); float rh = weatherData.getHumidity(); heatIndex = computeHeatIndex(t, rh); } display(); } }
3. 测试类不变
package weatherObservable; /** * 测试类 * @author wwj * */ public class WeatherStation { public static void main(String[] args) { //建立一个WeatherData对象 WeatherData weatherData = new WeatherData(); //第一个布告板 CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay( weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); // 模拟新的气象数据 weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } }
4. 但测试结果发生了变化:观察者被通知的次序发生了变化
Heat index is 82.95535 Forcast: Improving weather on the way! Avg/Max/Min temperature = 80.0/80.0/80.0 Current conditions: 80.0F degrees and 65.0% humidity Heat index is 86.90124 Forcast: Watch out for cooler, rainy weather Avg/Max/Min temperature = 81.0/82.0/80.0 Current conditions: 82.0F degrees and 70.0% humidity Heat index is 83.64967 Forcast: more of the same Avg/Max/Min temperature = 80.0/82.0/78.0 Current conditions: 78.0F degrees and 90.0% humidity
以上的实现被认为不是那么“正确”的,为什么呢?
有以下原因:
1. Observable是一个“类”,而不是一个接口,也没有实现一个接口,限制了它的使用和复用。
2. Observable将关键的方法保护起来了,违反了 “多用组合,少用继承”的设计原则。
当然在JDK中不只有这个地方用到了观察者模式,比如以下几个地方也用到了:
1. Swing
2. JavaBeans
3. RMI
好啦,第二个设计模式:观察者模式被小巫收入囊中,这实在太有趣了。
下一个模式将会是:装饰者模式。
相关推荐
我们说学习Java应该从Swing开始,那么学习Swing最重要的思想就是对于观察者模式的理解(Observer Pattern)。因为,该设计模式在Java Swing框架中贯穿了始终。对于C#的委托、代理概念所使用的Callback(回调模式--...
定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
撤销功能的实现——备忘录模式(三) 撤销功能的实现——备忘录模式(四) 撤销功能的实现——备忘录模式(五) 观察者模式-Observer Pattern 对象间的联动——观察者模式(一) 对象间的联动——观察者模式(二) ...
文章链接:https://blog.csdn.net/qq_44901285/article/details/116092808?spm=1001.2014.3001.5501 Spring事件机制(Event)-- 基于观察者模式实现多任务同时处理(源码)
设计模式之观察者模式ObserverPattern
从生活中的例子可以看出,只要对订阅号... 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的行为。
观察者模式(Observer Pattern)是一种对象行为型设计模式,它定义了对象之间的一对多依赖关系。 当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现分布式事件处理系统...
观察者模式 行为模式 在对象之间定义一对多的依赖关系,以便当一个对象更改状态时,将自动通知和更新其所有依赖关系。 在此示例中,我们要监视节点上的子创建/删除事件(可用于监视文件夹) 源代码源于以下UML图:
设计模式观察者 观察者设计模式示例程序。 日本公司的编码测试。 它是什么? 它是基于 Uzabase 公司 ( ) 分配的应用程序 可以在以下链接中找到作业(日文版): 我做的应用程序是新版本的uzabase_assignment.rar,...
观察者模式(Observer Pattern) 状态模式(State Pattern) 空对象模式(Null Object Pattern) 策略模式(Strategy Pattern) 模板模式(Template Pattern) 访问者模式(Visitor Pattern) 4. J2EE 模式 ...
1、策略模式STRATEGY PATTERN ...16、观察者模式OBSERVER PATTERN 17、责任链模式 18、访问者模式VISITOR PATTERN 19、状态模式 20、原型模式 21、中介者模式 22、解释器模式 23、亨元模式 24、备忘录模式
工厂方法模式(Factory Method Pattern) 观察者模式(Observer Pattern) 建造者模式(Builder Pattern) 解释器模式(Interpreter Pattern) 命令模式(Command Pattern) 模板方法模式(Template Method Pattern) 桥接模式...
23种设计模式(Design Pattern)的C++实现范例,包括下面列出的各种模式,代码包含较详细注释。...观察者模式(Observer) 状态模式(State) 策略模式(Strategy) 模板方法模式(Template Method) 访问者模式(Visitor)
设计模式(19)-Observer Pattern 178 一、 观察者(Observer)模式 178 二、 观察者模式的结构 179 三、 观察者模式的示意性源代码 180 四、 C#中的Delegate与Event 183 五、 一个实际应用观察者模式的例子 187 六...
观察者模式(Observer Pattern) 状态模式(State Pattern) 空对象模式(Null Object Pattern) 策略模式(Strategy Pattern) 模板模式(Template Pattern) 访问者模式(Visitor Pattern) 4 J2EE 模式 这些设计...
创建型模式用来处理对象的创建... 观察者模式(Observer Pattern) 状态模式(State Pattern) 策略模式(Strategy Pattern) 模板方法模式(Template Method Pattern) 访问者模式(Visitor Pattern)
设计模式(19)-Observer Pattern 一、 观察者(Observer)模式 二、 观察者模式的结构 三、 观察者模式的示意性源代码 四、 C#中的Delegate与Event 五、 一个实际应用观察者模式的例子 六、 观察者模式的优...
在设计一组依赖的对象与它们所依赖的对象之间一致(同步)的交流模型时,观察者模式(Observer Pattern)很有用。它可以使依赖对象的状态与它们所依赖的对象的状态保持同步。这组依赖的对象指的是观察者(Observer)...
观察者模式(Observer Pattern) 17. 解释器模式(Interpreter Pattern) 18. 中介者模式(Mediator Pattern) 19. 职责链模式(Chain of Responsibility Pattern) 20. 备忘录模式(Memento Pattern) 21. 策略模式...
主要介绍了JavaScript编程设计模式之观察者模式(Observer Pattern),简单说明了观察者模式的概念、原理并结合实例形式详细给出了观察者模式的相关实现与使用技巧,需要的朋友可以参考下