02觀察者模式

来源:https://www.cnblogs.com/yunshalee/archive/2023/04/12/17310807.html
-Advertisement-
Play Games

讓對象保持消息靈通 #01需求 一個WeatherData對象負責追蹤目前的天氣狀況(溫度,濕度,氣壓)。希望你們能建立一個應用,有三種佈告板,分別顯示目前的狀況、氣象統計及簡單的預報。當WeatherObject對象獲得最新的測量數據時,三種佈告板必須實時更新。而且,這是一個可以擴展的氣象站,We ...


讓對象保持消息靈通


01需求

一個WeatherData對象負責追蹤目前的天氣狀況(溫度,濕度,氣壓)。希望你們能建立一個應用,有三種佈告板,分別顯示目前的狀況、氣象統計及簡單的預報。當WeatherObject對象獲得最新的測量數據時,三種佈告板必須實時更新。而且,這是一個可以擴展的氣象站,Weather-O-Rama氣象站希望公佈一組API,好讓其他開發人員可以寫出自己的氣象佈告板,並插入此應用中,我們希望能提供這樣的API。

class WeatherData{
        public int getTemperature(){
        }
        public int getHumidity(){
        }
        public int getPressure(){
        }
        public void measurementsChanged(){
        //一旦氣象測量更新,此方法會被調用
        }
}

實現1

public class WeatherData {
    // 實例變數聲明
    public void measurementsChanged() {
       float temp = getTemperature();
       float humidity = getHumidity();
       float pressure = getPressure();
       currentConditionsDisplay.update(temp, humidity, pressure);
       statisticsDisplay.update(temp, humidity, pressure);
       forecastDisplay.update(temp, humidity, pressure);
    }
// 這裡是其他WeatherData方法
}

缺點:
>針對實現編程
對於每個新的顯示,都得修改這份代碼
沒有辦法在運行時添加/移除顯示元素
沒有封裝改變的部分

02觀察者模式

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

有幾種不同的實現方法,大多數圍繞著包括主題和觀察者介面的類設計

類圖:

第四個設計原則:為了交互對象之間松耦合設計而努力。
>主題只知道觀察者實現了某個介面(也就是Observer介面)
任何時候我們都可以增加新的觀察者。也可以在任何時候刪除某些觀察者。
有新類型的觀察者出現時,主題的代碼不需要修改,
獨立復用主題和觀察者
改變主題/觀察者其中一方,不會影響另一方

實現2

設計氣象站

實現氣象站

1.構建主題subject和觀察者observer介面

//主題介面
public interface Subject{
    //註冊觀察者
    public void registerObserver(Observer o);
    //刪除觀察者
    public void removeObserver(Observer o);
    //當主題狀態改變時,這個方法會被調用,以通知所有的觀察者
    public void notifyObserver();
}

public interface Observer {
    //當氣象觀測值改變時,主題會把這些狀態值當作方法的參數,傳送給觀察者
    public void update(float temp,float humidity,float pressure);
}

public interface DisplayElement{
    //當需要顯示時,調用此方法
    public void display();
}

2.WeatherData類實現主題介面

public class WeatherData implements Subject{
    
    private ArrayList<observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData(){
        observers=new ArrayList<observer>();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);//一個觀察者註冊的時候,把它添加到list的末端
    }

    @Override
    public void removeObserver(Observer o) {
        int i=observers.indexOf(o);//獲得對象索引
        if(i&gt;=0){
            observers.remove(i);
        }
    }

    @Override
    public void notifyObserver() {
        for(Observer observer:observers){
            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();
    }
    //WeatherData的其他方法
}

3.構造顯示元素
顯示類實現Observer介面,所以可以從WeatherData對象中獲取變化

public class CurrentConditionDisplay implements Observer,DisplayElement{
    private float temperature;
    private float humidity;
    private Subject weatherData;

    //構造器被傳入weatherData對象(Subject),用它來把 【顯示】 註冊為 【觀察者】
    public CurrentConditionDisplay(WeatherData weatherData){
        this.weatherData=weatherData;
        weatherData.registerObserver(this);
    }
    @Override
    public void display() {
        System.out.println("current conditions:" + temperature + "F degrees and " + humidity + "% humidity");
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature=temp;
        this.humidity=humidity;
        display();
    }
}

4.啟動氣象站

public class WeatherStation {
    public static void main(String[] args) {
       //創建對象
       WeatherData weatherData = new WeatherData();
      //創建顯示
       CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
      //模擬氣象測量
       weatherData.setMeasurements(80,65,30.4f);
    }
}

缺點:
>每次更新信息都會全部通知到每個觀察者,而觀察者只想要有用的信息;
不能擴展更多的顯示【因為觀察者介面的update方法是固定參數】

實現3(改進)

我們可以讓Observer按需要從Subject拉取。當Subiect的數據變化,我們馬上通過調用update()傳送數據,推送新的溫度、濕度和氣壓值給Observer。
為了切換到拉取方式,我們需要對已有代碼做一些小小的修改
Subject的發送通知.....
修改WeatherData中的notifyObservers()方法,不帶參數地調用Observer中的update()方法:

public void notifyobservers() {
  for(Observer observer:observers){
      observer.update();
  }
}

Observer的接收通知....
修改Observer介面,改變update()方法的簽名,這樣它就沒有參數了:

public interface Observer {
  public void update();
}

修改每個具體Observer,改變其各自的update0方法的簽名,並使用WeatherData的getter方法從Subject獲取氣象數據。CurrentConditionsDisplay類的新代碼如下:

public void update() {
  this.temperature = weatherData.getTemperature();
  this,humidity = weatherData.getHumidity();
  display();
}

總結

OO基礎:抽象
OO原則:
>封裝變化。
組合優於繼承
針對介面編程,而不是針對實現。
儘力達到交互對象之間的松耦合設計。【新增】

OO模式:
觀察者模式:定義對象之間的一對多依賴這樣,當一個對象改變狀態時,它的所有依賴者會被通知並自動更新。

要點

觀察者模式定義對象之間的一對多關係
主題使用通用介面更新觀察者。
任何具體類型的觀察者都可參與該模式,只要它們實現察者介面。
觀察者是松耦合的,除了知道它們實現觀察者介面之外,主題對它們的其他事情不知情
使用該模式時,你可以從主題推或拉數據(拉被認為更“正確”)
Swing大量使用觀察者模式許多GUI框架也是這樣。
你也會在其他很多地方發現該模式,包括RxJava、JavaBeans和RMI,以及其他語言的框架,像Cocoa、Swift和JavaScript事件。
觀察者模式和出版/訂閱模式相關。出版/訂閱模式用於更複雜得多主題和/或多消息類型的情形。
觀察者模式是一個常用的模式,當我們學習模型-視圖-控制器時,還會看到它。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 蘋果在iOS16.1系統對第三方開放了靈動島的API,並允許開發者基於靈動島開發相應軟體,越來越多的APP開始基於靈動島的交互進行設計和開發,本文將簡單介紹靈動島開發的流程和將其與業務場景相結合的思考。 ...
  • 首先說明簡易版是只有一個 倒計時 和一個 進度條,頁面載入後自動開始計時,下次計時需要手動刷新頁面。 後續會更新實現完整的倒計時功能的文章 前期準備 前端框架 你需要準備一些前端框架:Bootstrap4 和 jQuery 安裝方法請自行查閱官方文檔或教程 Bootstrap4:https://v4 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言: 梳理了一下項目中的PWA的相關用法,下麵我會正對vue2和vue3的用法進行一些教程示例,引入離線緩存機制,即使你斷網,也能訪問頁面。一旦用戶訪問了我們的網頁,我們就像牛皮糖一樣粘連著他,他永遠都可以訪問,即使斷網也能訪問。有一天 ...
  • 作者:京東零售 周明亮 寫在前面 這裡我們初步提到了一些基礎概念和應用: 分析器 抽象語法樹 AST AST 在 JS 中的用途 AST 的應用實踐 有了初步的認識,還有常規的代碼改造應用實踐,現在我們來詳細說說使用 AST, 如何進行代碼改造? Babel AST 四件套的使用方法 其實在解析 A ...
  • 當瀏覽器載入網頁時,通常會遵循一個預設的流程,先載入 HTML、CSS 和 JavaScript,然後再載入圖片、音頻、視頻等資源。這個預設的流程可能會導致網頁載入速度變慢,用戶體驗不佳。因此,可以使用一些技術來優化網頁載入的速度,其中之一就是按需載入。 按需載入是指根據用戶實際需要,動態地載入資源 ...
  • 1.準備工作:HbuiderX + 微信開發者工具下載安裝+小程式賬號申請開通(這裡就不例舉了,可以看同賬號uniapp小程式開發準備) 2.創建項目 新版本的HbuilderX點擊新建項目——選擇uni-app——選擇預設模板——輸入項目名稱——選擇Vue版本(此隨筆是前後端分離開發,不使用Uni ...
  • css基礎:塊元素、內聯元素、內聯塊元素 CSS中,html中的標簽元素大體被分為三種不同的類型:塊狀元素、內聯元素(又叫行內元素)和內聯塊狀元素。 1.常用的塊狀元素有: <div>、<p>、<h1>-<h6>、<ol>、<ul>、<dl>、<table>、<address>、<blockquot ...
  • 本文從攻擊者角度和防禦者角度詳細解析前端代碼安全與混淆的相關知識,總結了大部分攻擊者共同點以及如何應對普通開發者外掛程式和Pyhton 爬蟲 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...