設計模式之觀察者模式

客戶需求

/**
 * 需求: 
 * 
 * 氣象站提供最新的天氣預報信息,包括: 溫度、濕度、氣壓,這些信息一發生變化, 客戶端的信息需要同時更新 請用代碼實現模擬實現該功能
 * 
 * 
 */

程序設計

一個氣象站對應著多個客戶端,氣象站的數據一發生變化,客戶端的數據也要隨著更新,這就形成了一種依賴關系,并且是一對多的關系,很顯然,我們可以用觀察者模式來完成此功能

基本概念

  • 定義

定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知并自動更新

  • 角色

    • 抽象被觀察者(或者叫主題)

    它是一個接口或者抽象類,用來把所有觀察者對象的引用保存到一個集合中。定義三個方法:注冊觀察者、解除觀察者、通知觀察者;這三個方法就是被觀察者與觀察者通信的橋梁

    • 抽象觀察者

    為所有的具體的觀察者定義的一個接口,定義一個方法:更新;用于獲取被觀察者發生變化時更新自己

    • 具體的被觀察者(或者叫主題)

    在被觀察者內部狀態發生變化,通知所有注冊過的的觀察者。通常實現或繼承抽象被觀察者

    • 具體的觀察者

    實現抽象觀察者接口,使自己與具體的被觀察者的狀態保持一致

  • 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 設計模式

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 觀察者模式 Rxjava中運用到了觀察者模式,那什么是觀察者模式呢,現在來學習一下。正所謂觀察,就是看,細察事物的...
    cgzysan閱讀 572評論 0 4
  • 前言定義:觀察者設計模式定義了對象間的一種一對多的依賴關系,以便一個對象的狀態發生變化時,所有依賴于它的對象都得到...
    xsp單細胞閱讀 463評論 0 1
  • 在下載模塊中經常要用到的一個模式就是觀察者模式了,這是為了提高用戶體驗所決定的。 但用戶在下載頁面點擊了下載之后,...
    寶塔山上的貓閱讀 469評論 0 2
  • 七年啊 從今天開始你就十七歲了 歷經完十六歲的天空你即將迎來新的自己了 怎么樣 十七歲的你想成為一個怎樣的女孩擁...
    七年盛夏閱讀 992評論 0 2
  • 安昌古鎮是浙江紹興四大古鎮之一,典型的江南水鄉特色,最有特色的是安昌的小橋。 補充說明:紹興是中國國內保存古橋數量...
    haitaopengpai閱讀 427評論 0 5