天天看點

Day55-設計模式-觀察者模式

title: Day55-設計模式-觀察者模式

date: 2021-03-26 15:46:29

author: Liu_zimo

設計模式

  • 設計模式分為三種類型,共23種
    1. 建立型模式:單例模式、抽象工廠模式、原型模式、建造者模式、工廠模式。
    2. 結構型模式:擴充卡模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。
    3. 行為型模式:模版方法模式、指令模式、通路者模式、疊代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式(Interpreter模式)、狀态模式、政策模式、職責鍊模式(責任鍊模式)。

觀察者模式

  • 天氣預報項目需求
    1. 氣象站可以将每天測量到的溫度,濕度,氣壓等等以公告的形式釋出出去(比如釋出到自己的網站或第三方)
    2. 需要設計開放型API,便于其他第三方也能接入氣象站擷取資料
    3. 提供溫度、氣壓和濕度的接口
    4. 測量資料更新時,要能實時的通知給第三方
  • 普通方案
    • 通過對氣象站項目的分析,我們可以初步設計出一個WeatherData類
    1. 通過getXxx方法,可以讓第三方接入,并得到相關資訊
    2. 當資料有更新時,氣象站通過調用dataChange()去更新資料,當第三方再次擷取時,就能得到最新資料,當然也可以推送。
    • 問題分析:
      1. 其他第三方接入氣象站擷取資料的問題
      2. 無法在運作時動态的添加第三方(新浪網站)
      3. 違反ocp原則 => 觀察者模式
    • 在WeatherData中,當增加一個第三方,都需要建立一個對應的第三方的公告闆對象,并加入到dataChange,不利于維護,也不是動态加入
package com.zimo.設計模式.行為型模式.觀察者模式.普通方案;
/**
 * 設計模式 - 觀察者模式:天氣預報案例 - 普通方案
 *      目前氣象情況
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 16:37
 */
public class CurrentConditions {
    private float temperature;  // 溫度
    private float pressure;     // 氣壓
    private float humidity;     // 濕度
    // 由WeatherData調用,推送模式
    public void update(float temperature, float pressure, float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        this.display();
    }
    public void display(){
        System.out.println("--- today mT:" + this.temperature + "---");
        System.out.println("--- today mP:" + this.pressure + "---");
        System.out.println("--- today mH:" + this.humidity + "---");
    }
}
----------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.普通方案1;
/**
 * 設計模式 - 觀察者模式:天氣預報案例 - 普通方案
 *      氣象資料類 - 核心類
 *      1.包含最新的天氣情況  2.含有CurrentConditions對象
 *      3.當資料有更新時,就主動的調用CurrentConditions對象update方法(含display),這樣他們(接入方)就看到最新的資訊
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 16:10
 */
public class WeatherData {
    private float temperature;  // 溫度
    private float pressure;     // 氣壓
    private float humidity;     // 濕度
    private CurrentConditions currentConditions;
    public WeatherData(CurrentConditions currentConditions) { this.currentConditions = currentConditions; }
    public float getTemperature() { return temperature; }
    public float getPressure() { return pressure; }
    public float getHumidity() { return humidity; }
    public void dataChange(){ currentConditions.update(getTemperature(), getPressure(), getHumidity()); }
    // 當資料更新時,調用setData
    public void setData(float temperature, float pressure, float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        // 将最新的資訊推送給接入方
        dataChange();
    }
}
----------------------------------------------------------------------------
public static void main(String[] args) {
    // 建立一個接入方
    CurrentConditions currentConditions = new CurrentConditions();
    WeatherData weatherData = new WeatherData(currentConditions);
    weatherData.setData(30, 150, 40);
    System.out.println("天氣變更");
    weatherData.setData(40, 160, 20);
}
           

觀察者模式原理

  • 觀察者模式類似訂牛奶業務
    1. 牛奶站/氣象局:Subject
    2. 使用者/第三方網站:Observer
  • Subject:登記注冊、移除和通知
    1. registerObserver 注冊
    2. removeObserver 移除
    3. notifyObservers()通知所有的注冊的使用者,根據不同需求,可以是更新資料,讓使用者來取,也可能是實施推送,看具體需求定
  • Observer:接收輸入
  • 觀察者模式:對象之間多對一依賴的一種設計方案,被依賴的對象為Subject,依賴的對象為Observer,Subject通知Observer變化,比如這裡的奶站是

    Subject,是1的一方。使用者時Observer,是多的一方。

Day55-設計模式-觀察者模式
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
 * 設計模式 - 觀察者模式:天氣預報案例
 *      觀察者接口
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 17:20
 */
public interface Observer {
    public void update(float temperature,float pressure, float humidity);
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
 * 設計模式 - 觀察者模式:天氣預報案例
 *      氣象站
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 17:17
 */
public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
import com.zimo.設計模式.行為型模式.觀察者模式.普通方案.CurrentConditions;
import java.util.ArrayList;
/**
 * 設計模式 - 觀察者模式:天氣預報
 *      氣象資料類 - 核心類
 *      1.包含最新的天氣情況  2.含有觀察者集合,使用ArrayList管理
 *      3.當資料有更新時,就主動的調用ArrayList,通知所有的(接入方)看到最新的資訊
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 17:24
 */
public class WeatherData implements Subject{
    private float temperature;  // 溫度
    private float pressure;     // 氣壓
    private float humidity;     // 濕度
    private ArrayList<Observer> observers;
    public WeatherData() { this.observers = new ArrayList<>(); }
    public void dataChange(){ notifyObservers(); }
    // 當資料更新時,調用setData
    public void setData(float temperature, float pressure, float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        // 将最新的資訊推送給接入方
        dataChange();
    }
    @Override   // 注冊一個觀察者
    public void registerObserver(Observer o) { observers.add(o); }
    @Override   // 移除一個觀察者
    public void removeObserver(Observer o) { if (observers.contains(o)) observers.remove(o); }
    @Override
    public void notifyObservers() {
        for (Observer observer : this.observers) {
            observer.update(this.temperature, this.pressure, this.humidity);
        }
    }
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
 * 設計模式 - 觀察者模式:天氣預報
 *      目前氣象情況
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 17:23
 */
public class CurrentConditions implements Observer{
    private float temperature;  // 溫度
    private float pressure;     // 氣壓
    private float humidity;     // 濕度
    // 由WeatherData調用,推送模式
    public void update(float temperature, float pressure, float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        this.display();
    }
    public void display(){
        System.out.println("--- today mT:" + this.temperature + "---");
        System.out.println("--- today mP:" + this.pressure + "---");
        System.out.println("--- today mH:" + this.humidity + "---");
    }
}
--------------------------------------------------------------------------
package com.zimo.設計模式.行為型模式.觀察者模式.天氣預報;
/**
 * 設計模式 - 觀察者模式:天氣預報
 *      百度接入
 * @author Liu_zimo
 * @version v0.1 by 2021/3/26 17:37
 */
public class BaiduSite implements Observer{
    private float temperature;  // 溫度
    private float pressure;     // 氣壓
    private float humidity;     // 濕度
    public void update(float temperature, float pressure, float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        this.display();
    }
    public void display(){
        System.out.println("--- baidu mT:" + this.temperature + "---");
        System.out.println("--- baidu mP:" + this.pressure + "---");
        System.out.println("--- baidu mH:" + this.humidity + "---");
    }
}
--------------------------------------------------------------------------
public static void main(String[] args) {
    WeatherData weatherData = new WeatherData();
    CurrentConditions currentConditions = new CurrentConditions();
    BaiduSite baiduSite = new BaiduSite();
    weatherData.registerObserver(currentConditions);
    weatherData.registerObserver(baiduSite);
    weatherData.setData(10, 100, 30);
    weatherData.removeObserver(currentConditions);
    weatherData.setData(30, 200, 20);
}
           
  • 觀察者模式的好處:
    1. 觀察者模式設計後,會以集合的方式來管理使用者(Observer),包括注冊,移除和通知
    2. 這樣,我們增加觀察者(這裡可以了解成一個新的公告闆),就不需要去修改核心類WeatherData不會修改代碼,遵守了ocp原則

JDK中應用源碼分析

  • JDK的Observable類就使用了觀察者模式
  • Observable的作用和地位 ===>>> Subject
  • Observable是類,不是接口,類中已經實作了核心的方法,即管理Observer的方法add… delete… notify…
  • Observer的作用和地位 ===>>> Observer,有update
  • Observable和 Observer的使用方法和前面講過的一樣,隻是Observable是類,通過繼承來說實作觀察者模式