设计模式之观察者模式

客户需求

/**
 * 需求: 
 * 
 * 气象站提供最新的天气预报信息,包括: 温度、湿度、气压,这些信息一发生变化, 客户端的信息需要同时更新 请用代码实现模拟实现该功能
 * 
 * 
 */

程序设计

一个气象站对应着多个客户端,气象站的数据一发生变化,客户端的数据也要随着更新,这就形成了一种依赖关系,并且是一对多的关系,很显然,我们可以用观察者模式来完成此功能

基本概念

  • 定义

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新

  • 角色

    • 抽象被观察者(或者叫主题)

    它是一个接口或者抽象类,用来把所有观察者对象的引用保存到一个集合中。定义三个方法:注册观察者、解除观察者、通知观察者;这三个方法就是被观察者与观察者通信的桥梁

    • 抽象观察者

    为所有的具体的观察者定义的一个接口,定义一个方法:更新;用于获取被观察者发生变化时更新自己

    • 具体的被观察者(或者叫主题)

    在被观察者内部状态发生变化,通知所有注册过的的观察者。通常实现或继承抽象被观察者

    • 具体的观察者

    实现抽象观察者接口,使自己与具体的被观察者的状态保持一致

  • UML图

ObserverPattern.png
  • DemoOne

    • 被观察者

        public interface Subject
        {
            public void registerObserver(Observer observer);
        
            public void unregisterObserver(Observer observer);
        
            public void notifyObservers();
        }
      
    • 观察者

        public interface Observer
        {
            public void update(float temp, float humidity, float pressure);
        }
      
    • 具体被观察者

        public class WeatherDataSubject implements Subject
        {
            private float               temperature;
            private float               humidity;
            private float               pressure;
            /**
             * 记录所有的观察者
             */
            private ArrayList<Observer> observers;
        
            public WeatherDataSubject() {
                observers = new ArrayList<>();
            }
        
            @Override
            public void registerObserver(Observer observer)
            {
                observers.add(observer);
            }
        
            @Override
            public void unregisterObserver(Observer observer)
            {
                int indexOf = observers.indexOf(observer);
                if (indexOf >= 0)
                {
                    observers.remove(indexOf);
                }
            }
        
            @Override
            public void notifyObservers()
            {
                for (int i = 0; i < observers.size(); i++)
                {
                    Observer observer = observers.get(i);
                    observer.update(temperature, humidity, pressure);
                }
            }
        
            public void setMeasurements(float temperature, float humidity, float pressure)
            {
                this.temperature = temperature;
                this.humidity = humidity;
                this.pressure = pressure;
                notifyObservers();
            }
        
        }
      
    • 具体观察者

        public class CurrentConditionsDidsplay implements Observer
        {
            @Override
            public void update(float temp, float humidity, float pressure)
            {
                System.out.println("temperature=" + temp + "\t humidity=" + humidity + "\t pressure=" + pressure);
            }
        }
      
    • 测试

        public class ObserverPatternTest
        {
            public static void main(String[] args)
            {
                WeatherDataSubject subject = new WeatherDataSubject();
                CurrentConditionsDidsplay condition = new CurrentConditionsDidsplay();
                subject.registerObserver(condition);
                subject.setMeasurements(23.0f, 1.0f, 350.0f);
            }
        }
      

以上这种方式只是简单的实现了被观察者数据发生变化时,主动将数据送过来,是一种推的模式。它不会管观察者到底需不需要全部的数据。但是,有的观察者可能只需要一点点数据,不想收到一堆数据,那此时怎么办呢?那被观察者是否可以提供一个get方法让观察者自己去获取数据,仅通知数据有变化了?接下来我们看看Java内置的观察者模式

  • UML图
Java_ObserverPattern.png
  • DemoTwo
    • 具体的被观察者

      public class WeatherDataObservable extends Observable
      {
          private float   temperature;
          private float   humidity;
          private float   pressure;
      
          public void setMeasurements(float temperature, float humidity, float pressure)
          {
              this.temperature = temperature;
              this.humidity = humidity;
              this.pressure = pressure;
              //仅仅是用来通知观察者我的状态发生变化了
              setChanged();
              notifyObservers();
          }
      
          public float getTemperature()
          {
              return temperature;
          }
      
          public float getHumidity()
          {
              return humidity;
          }
      
          public float getPressure()
          {
              return pressure;
          }
      }
      
    • 具体的观察者

      public class CurrentConditionsDidsplayObserver implements Observer
      {
      
          @Override
          public void update(Observable observable, Object obj)
          {
              if (observable instanceof WeatherDataObservable)
              {
                  WeatherDataObservable data = (WeatherDataObservable) observable;
                  float temperature = data.getTemperature();
                  float humidity = data.getHumidity();
                  float pressure = data.getPressure();
                  System.out.println("temperature=" + temperature + "\t humidity=" + humidity + "\t pressure=" + pressure);
              }
          }
      }
      

java内置的观察者模式是属于拉数据模式,被观察者状态发生变化了,通过setChanged方法仅通知观察者状态发生了变化,拉不拉数据是观察者的事了,与被观察者无关了。但是这种设计方式也会有一定的限制:

(1)Observable是一个类,所以我们的子类需继承它,若此时被观察者需同时继承另一个超类,就会陷入两难了,毕竟Java不支持多重继承,这限制了Observable的复用能力

(2)Observable中的setChanged方法被protected了,这意味着:除非你继承Observable类,否则你无法创建Observable实例并组合到你自己的对象中来。“多用组合,少用继承”

知识总结

这两种模式的使用,取决于系统设计时的需要。如果观察者比较复杂,并且观察者进行更新时必须得到一些具体变化的信息,则“推模式”比较合适。如果观察者比较简单,则“拉模式”就比较适合。

参考资料

Head First 设计模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 观察者模式 Rxjava中运用到了观察者模式,那什么是观察者模式呢,现在来学习一下。正所谓观察,就是看,细察事物的...
    cgzysan阅读 542评论 0 4
  • 前言定义:观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到...
    xsp单细胞阅读 444评论 0 1
  • 在下载模块中经常要用到的一个模式就是观察者模式了,这是为了提高用户体验所决定的。 但用户在下载页面点击了下载之后,...
    宝塔山上的猫阅读 446评论 0 2
  • 七年啊 从今天开始你就十七岁了 历经完十六岁的天空你即将迎来新的自己了 怎么样 十七岁的你想成为一个怎样的女孩拥...
    七年盛夏阅读 937评论 0 2
  • 安昌古镇是浙江绍兴四大古镇之一,典型的江南水乡特色,最有特色的是安昌的小桥。 补充说明:绍兴是中国国内保存古桥数量...
    haitaopengpai阅读 383评论 0 5