观察者模式

打印 上一主题 下一主题

主题 874|帖子 874|积分 2622

观察者模式

案例引入

要求

气象站案例要求

  • 1.气象站,可以将每天测量到的湿度,温度,气压等气象信息以公告的形式发布出去(发布到自己的网站或者第三方平台)。
  • 2.需要设计开发新的api,便于其他第三方也能接入气象站的数据。
  • 3.提供温度,气压,湿度的接口。
  • 4.策略的数据更新后,实时的通知第三方。
普通方案实现案例

通过对气象项目的分析,我们可以初步设计一个WeatherData类。有温度(temperature),湿度(humidity),气压(pressure)三个属性,还有dataChange方法。

  • 1.通过getXxx方法,可以让第三方接入,并得到相关信息。
  • 2.气象站定时的调用dataChange()去更新数据,在数据更新时,当第三方再次获取时,就能得到最新的数据,当然也可以推送数据,即定时的将数据,推送到目标网站上。
代码实现
  1. /**
  2. * 1.核心类,包含最新的天气信息数据,可以推送给别人
  3. * 2.含有 private CurrentConditions currentConditions;
  4. * 3.数据更新时,主动调用currentConditions进行数据推送,这样接入方,就会及时看到最新数据
  5. *
  6. * @author 长名06
  7. * @version 1.0
  8. */
  9. public class WeatherData {
  10.     //温度
  11.     private float temperature;
  12.     //气压
  13.     private float pressure;
  14.     //湿度
  15.     private float humidity;
  16.     private CurrentConditions currentConditions;
  17.     public WeatherData(CurrentConditions c) {
  18.         this.currentConditions = c;
  19.     }
  20.     public float getTemperature() {
  21.         return temperature;
  22.     }
  23.     public float getPressure() {
  24.         return pressure;
  25.     }
  26.     public float getHumidity() {
  27.         return humidity;
  28.     }
  29.     public void dataChange() {
  30.         currentConditions.update(getTemperature(), getPressure(), getHumidity());
  31.     }
  32.     //当数据有更新时,就调用这个setData
  33.     public void setData(float temperature, float pressure, float humidity) {
  34.         this.temperature = temperature;
  35.         this.pressure = pressure;
  36.         this.humidity = humidity;
  37.         //信息改变时,将最新信息,推送给接入方
  38.         dataChange();
  39.     }
  40. }
  41. /**
  42. * 显示今天天气情况,气象站自己的网站
  43. * @author 长名06
  44. * @version 1.0
  45. */
  46. public class CurrentConditions {
  47.     //温度
  48.     private float temperature;
  49.     //气压
  50.     private float pressure;
  51.     //湿度
  52.     private float humidity;
  53.     //更新数据 由WeatherData来调用,
  54.     public void update(float temperature,float pressure,float humidity){
  55.         this.temperature = temperature;
  56.         this.pressure = pressure;
  57.         this.humidity = humidity;
  58.         display();
  59.     }
  60.     //展示数据
  61.     public void display(){
  62.         System.out.println("今天温度" + temperature);
  63.         System.out.println("今天气压" + pressure);
  64.         System.out.println("今天湿度" + humidity);
  65.     }
  66. }
  67. /**
  68. * 观察者模式
  69. * @author 长名06
  70. * @version 1.0
  71. */
  72. public class Client {
  73.     public static void main(String[] args) {
  74.         CurrentConditions currentConditions = new CurrentConditions();
  75.         WeatherData weatherData = new WeatherData(currentConditions);
  76.         weatherData.setData(30,100,25);
  77.         System.out.println("=====天气变化=====");
  78.         weatherData.setData(35,100,30);
  79.     }
  80. }
复制代码
问题分析


  • 1.无法在运行时,动态的添加第三方。
  • 2.在WeatherData中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到dataChange,不利于维护,也不是动态加入。
  • 3.违反了ocp(开闭原则),=> 使用观察者模式。
观察者模式原理

观察者模式,类似订牛奶的业务,在观察者模式下,有以下角色,奶站/气象局(Subject),用户/第三方网站(Observer),Subject中有登记注册,移除和通知接口方法,register()注册,remove()移除,notify()通知注册用户,根据不同需求,不同实现,可以通知用户取数据,也可以推送给用户数据,也可以更新数据,Observer中接收输入,也就是修改数据的方法update()。
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer数据变化,类似定牛奶的业务,Subject是1,Observer是多。
观察者模式实现案例

uml图


代码实现
  1. /**
  2. * @author 长名06
  3. * @version 1.0
  4. */
  5. public interface Subject {
  6.     public void register(Observer o);
  7.     public void remove(Observer o);
  8.     public void notifies();
  9. }
  10. public interface Observer {
  11.     public void update(float temperature,float pressure,float humidity);
  12. }
  13. /**
  14. *  1.核心类,包含最新的天气信息数据,可以推送给别人
  15. *  2.含有 观察者集合。使用ArrayList管理
  16. *  3.数据更新时,主动调用观察者集合进行数据推送,这样接入方,就会及时看到最新数据
  17. * @author 长名06
  18. * @version 1.0
  19. */
  20. public class WeatherData implements Subject{
  21.     //温度
  22.     private float temperature;
  23.     //气压
  24.     private float pressure;
  25.     //湿度
  26.     private float humidity;
  27.     private List<Observer> observers = new ArrayList<>();
  28.     public float getTemperature() {
  29.         return temperature;
  30.     }
  31.     public float getPressure() {
  32.         return pressure;
  33.     }
  34.     public float getHumidity() {
  35.         return humidity;
  36.     }
  37.     public void dataChange(){
  38.         notifies();//通知所有注册用户
  39.     }
  40.     //当数据有更新时,就调用这个setData
  41.     public void setData(float temperature, float pressure, float humidity) {
  42.         this.temperature = temperature;
  43.         this.pressure = pressure;
  44.         this.humidity = humidity;
  45.         //信息改变时,将最新信息,推送给接入方
  46.         dataChange();
  47.     }
  48.     @Override
  49.     public void register(Observer o) {
  50.         observers.add(o);
  51.     }
  52.     @Override
  53.     public void remove(Observer o) {
  54.         if(observers.contains(o)) {
  55.             observers.remove(o);
  56.         }
  57.     }
  58.     @Override
  59.     public void notifies() {
  60.         for(Observer o : observers){
  61.             o.update(this.temperature,this.pressure,this.humidity);
  62.         }
  63.     }
  64. }
  65. public class TenXun implements Observer{
  66.     //温度
  67.     private float temperature;
  68.     //气压
  69.     private float pressure;
  70.     //湿度
  71.     private float humidity;
  72.     //更新数据 由WeatherData来调用,
  73.     @Override
  74.     public void update(float temperature,float pressure,float humidity){
  75.         this.temperature = temperature;
  76.         this.pressure = pressure;
  77.         this.humidity = humidity;
  78.         display();
  79.     }
  80.     //展示数据
  81.     public void display(){
  82.         System.out.println("====腾讯网站====");
  83.         System.out.println("腾讯 今天温度" + temperature);
  84.         System.out.println("腾讯 今天气压" + pressure);
  85.         System.out.println("腾讯 今天湿度" + humidity);
  86.     }
  87. }
  88. /**
  89. * @author 长名06
  90. * @version 1.0
  91. */
  92. public class XingLang implements Observer{
  93.     //温度
  94.     private float temperature;
  95.     //气压
  96.     private float pressure;
  97.     //湿度
  98.     private float humidity;
  99.     //更新数据 由WeatherData来调用,
  100.     @Override
  101.     public void update(float temperature,float pressure,float humidity){
  102.         this.temperature = temperature;
  103.         this.pressure = pressure;
  104.         this.humidity = humidity;
  105.         display();
  106.     }
  107.     //展示数据
  108.     public void display(){
  109.         System.out.println("====新浪网站====");
  110.         System.out.println("新浪 今天温度" + temperature);
  111.         System.out.println("新浪 今天气压" + pressure);
  112.         System.out.println("新浪 今天湿度" + humidity);
  113.     }
  114. }
  115. public class Baidu implements Observer {
  116.     //温度
  117.     private float temperature;
  118.     //气压
  119.     private float pressure;
  120.     //湿度
  121.     private float humidity;
  122.     //更新数据 由WeatherData来调用,
  123.     @Override
  124.     public void update(float temperature,float pressure,float humidity){
  125.         this.temperature = temperature;
  126.         this.pressure = pressure;
  127.         this.humidity = humidity;
  128.         display();
  129.     }
  130.     //展示数据
  131.     public void display(){
  132.         System.out.println("====百度网站====");
  133.         System.out.println("百度 今天温度" + temperature);
  134.         System.out.println("百度 今天气压" + pressure);
  135.         System.out.println("百度 今天湿度" + humidity);
  136.     }
  137. }
  138. /**
  139. * @author 长名06
  140. * @version 1.0
  141. */
  142. public class Client {
  143.     public static void main(String[] args) {
  144.         WeatherData weatherData = new WeatherData();
  145.         Baidu baidu = new Baidu();
  146.         TenXun tenXun = new TenXun();
  147.         XingLang xingLang = new XingLang();
  148.         weatherData.register(baidu);
  149.         weatherData.register(tenXun);
  150.         weatherData.register(xingLang);
  151.         weatherData.setData(20,100,30.3F);
  152.         weatherData.remove(xingLang);
  153.         System.out.println("====某个用户不订阅了====");
  154.         weatherData.setData(20,100,30.3F);
  155.     }
  156. }
复制代码
观察者模式优势

1.使用观察者模式后,以集合的形式来管理用户(Observer),包括注册,移除和通知。
2.这样我们增加观察者(可以理解为一个新的用户),就不需要取修改核心类,WeatherData不用修改代码,遵守了ocp。
观察者模式在JDK源码分析

1.JDK的ObServable类就使用了观察者模式。


2.角色分析
​        2.1 Observable的作用和地位等价于我们前面讲过的Subject.
​        2.2 Observable是类,不是接口,类中也实现了核心的方法,即管理Observable的方法,add,remove,notify等。
​        2.3 Observer的作用和地位等价于我们前面讲过的Observer,有update。
​        2.4 Observable和Observer的使用方法和前面讲过的一样,只是Observable是类,通过继承来实现观察者模式。
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

花瓣小跑

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表