設計模式(2)--觀察者模式

来源:http://www.cnblogs.com/simfg/archive/2017/04/24/6757911.html
-Advertisement-
Play Games

什麼是觀察者模式 舉個例子來簡單說明下這個模式:假如現在你在一家報社訂閱了報紙,每當有新的期刊,那麼他們就會把報紙送到你家,如果你什麼時候不想看這一期刊的時候,你就可以取消訂閱,那麼這時候他們就不會將報紙送到你家了。這其實就是利用了觀察者模式,先給出兩個基本概念:主題,就相當於被觀察的對象,這裡指的 ...


什麼是觀察者模式

  舉個例子來簡單說明下這個模式:假如現在你在一家報社訂閱了報紙,每當有新的期刊,那麼他們就會把報紙送到你家,如果你什麼時候不想看這一期刊的時候,你就可以取消訂閱,那麼這時候他們就不會將報紙送到你家了。這其實就是利用了觀察者模式,先給出兩個基本概念:主題,就相當於被觀察的對象,這裡指的就是報社;觀察者,實時接收主題新的數據,這裡指的就是訂閱報紙的人。

深入理解觀察者模式

  先給出一個問題,然後我們就根據這個問題進行討論。

  問題:現在有個氣象站,給一些氣象顯示器實時發送數據,氣象顯示器所顯示的數據方式不一樣,有些可能著重溫度或者濕度,客戶也可以根據自己的需求來開發一份氣象顯示器。

  根據這個問題,你的代碼可能是這樣的:

  以下代碼不是一個文件

//TemperatureDisplay.java 
public class TemperatureDisplay {

    public void update(float temperature, float humidity, float pressure) {
        System.out.println("temperature is " + temperature);
    }
}

//HumidityDisplay.java 
public class HumidityDisplay {

    public void update(float temperature, float humidity, float pressure) {
        System.out.println("humidity is " + humidity);
    }
}

//MixDisplay.java 
public class MixDisplay {

    public void update(float temperature, float humidity, float pressure) {
        System.out.println("temperature is " + temperature);
        System.out.println("humidity is " + humidity);
        System.out.println("pressure is " + pressure);
    }
}

//WeatherData.java
public class WeatherData {

    private float temperature;

    private float humidity;

    private float pressure;

    private TemperatureDisplay temperatureDisplay;

    private HumidityDisplay humidityDisplay;

    private MixDisplay mixDisplay;

    public WeatherData() {
    }

    public WeatherData(TemperatureDisplay temperatureDisplay, HumidityDisplay humidityDisplay,
            MixDisplay mixDisplay) {
        super();
        this.temperatureDisplay = temperatureDisplay;
        this.humidityDisplay = humidityDisplay;
        this.mixDisplay = mixDisplay;
    }

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

        //當氣象數據變更時調用      
    public void measurementsChange() {
        temperatureDisplay.update(temperature, humidity, pressure);
        humidityDisplay.update(temperature, humidity, pressure);
        mixDisplay.update(temperature, humidity, pressure);
    }
}

  這可能是你最初的想法,或許你的想法比這個更好

  我們來仔細看下上面的代碼,你會發現這個代碼的擴展性很差。如果有人想自定義一個氣象顯示器,那麼你必須修改WeatherData這個類中的代碼,顯然這個代碼是不可以讓其他人隨便進行修改的,因為這個是氣象站提供的。所以氣象站的設計人員肯定就需要重構這一代碼。

 

  解決方案:

  我們發現這個氣象站就好像是主題一樣,而氣象顯示器就貌似是觀察者。你們是怎麼看的呢?

  看看氣象顯示器的代碼,發現都只有一個update方法,當然你可以添加其他的方法,那麼我們就可以定義一個介面Display,讓所有的氣象顯示器都實現這個介面。然後在WeatherData類中添加一個集合屬性,這個集合中包含的是Display這一類型的對象。

  為了可擴展性,可能有很多氣象站,所以我們定義一個Subject的介面,該介面中主要有三個方法,分別是註冊氣象顯示器、刪除註冊氣象顯示器、通知註冊氣象顯示器,即registerObverse、removeObverse、notifyObverse。而每個氣象顯示器中增加一個都必須有一個Subject類型的屬性,並且在構造方法中需要傳遞一個Subject類型的參數進行實例化這個對象,然後這個氣象顯示器在這個主題中進行註冊。

  根據這個方案,示例代碼如下:

//Subject.java
public interface Subject {

    void registerObverse();

    void removeObverse();

    void notifyObverse();
}

//Display.java
//這就是一個觀察者類的介面
public interface Display {

    void update(float temperature, float humidity, float pressure);
}

//WeatherData.java
import java.util.ArrayList;
import java.util.List;

public class WeatherData implements Subject {

    private float temperature;

    private float humidity;

    private float pressure;

    private List<Display> displays;

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

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    @Override
    public void registerObverse(Display display) {
        displays.add(display);
    }

    @Override
    public void removeObverse(Display display) {
        int i = displays.indexOf(display);
        if(i>=0)
            displays.remove(display);
    }

    @Override
    public void notifyObverse() {
        for(Display display:displays){
            display.update(temperature, humidity, pressure);
        }
    }

    //當氣象數據變化時就修改調用這一方法
    public void measurementsChanged(){
        notifyObverse();
    }
    
}

//MixDisplay.java
//這裡寫了一個氣象顯示器,其他的跟著類似
public class MixDisplay implements Display {

    private Subject subject;

    public MixDisplay(Subject subject) {
        this.subject = subject;
        subject.registerObverse(this);
    }

    public void remove() {
        subject.removeObverse(this);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        System.out.println("temperature is " + temperature);
        System.out.println("humidity is " + humidity);
        System.out.println("pressure is " + pressure);
    }

}

  這時候如果你想自定義一個顯示器,只需要實現Display這一介面就可以了,然後在氣象顯示器中定義一個Subject類型的屬性,然後在構造是進行註冊該觀察者,那麼只要氣象數據變化了你就可以接受到。這是不是具有很好的可擴展性呢?

  其實呢Java中內置中就包含了這一模式,其主題就是Observable(這是一個類),觀察者則是Obverse(這是一個介面)。

  所以你可以試試用內置的這一模式實現下以上案例。

  如果你對該博客有什麼見解或疑問,可以留言哦>v<


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

-Advertisement-
Play Games
更多相關文章
  • 靜態工廠方法是一種將類的運用者和產生著隔離的設計模式,它是一種創造型模式,但是它不屬於23種基本設計模式中的一種,它是理解抽象工廠的基礎 "參考yqj2065的博客" 上課時yqj2065要求:除了JDK等框架或工具中的類,自己編寫的類不得使用new創建對象(Test除外)。 據說是因為使用new會 ...
  • 概述: GOF定義:給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。 在軟體開發特別是DSL開發中常常需要使用一些相對較複雜的業務語言,如果業務語言使用頻率足夠高,且使用普通的編程模式來實現會導致非常複雜的變化,那麼就可以考慮使用解釋器模式構建一個解釋 ...
  • 讀完了這本書,收穫很多,對程式設計有了很多新的理解。將每章模式的大概要點做了些筆記以備查閱,一些設計模式書讀完也對其瞭解得不是很透徹,需要以後在實踐中來不斷地加深理解吧。讀書過程中用Java跟著實踐了些部分模式的代碼上傳到了 "https://github.com/wanghaoxi3000/des ...
  • 1、使用Eclipse 建立Maven項目(webapp OR quickstart) 2、配置Maven,如下: 3、建立啟動Application 4、編輯Controller 5、通過application.properties對項目進行配置 項目文件佈局如下: 啟動Application程式 ...
  • 現象: 同事負責的項目轉到我的頭上,整理服務過程中發現了隊列的積壓問題。 為了搞清楚積壓的嚴重程度, 對隊列任務數每分鐘進行一次採樣,生成一個走勢圖, 隊列積壓情況一目瞭然,非常嚴重。 分析: 聽了同事對系統的介紹,猜測是mongo性能影響了處理效率,於是針對mongo進行分析 1. 使用mongo ...
  • 1. 前言 2. 所謂習慣認知 3. 開門見山的萬金油 第1條:抽象類設計註重對象性,介面設計註重服務性 第2條:更近的抽象類,更遠的介面 第3條:子類間有關係時考慮用抽象類,沒有關係時一定要用介面 第4條:版本迭代中優先考慮使用抽象類而不是介面 4. 設計是個性的妥協 5. 參考資料 1. 前言 ...
  • 程式優化是用於消除程式中大量的if else這種判斷語句 ...
  • 歷時兩個多月的時間,終於把effective c++又複習了一遍,比較慢,看的是英文版,之前看的時候做過一些筆記,但不夠詳細,這次筆者是從頭到尾的翻譯了一遍,加了一些標題,先記錄到word裡面,然後發佈到博客園上。這麼做是為了方便查閱,複習C++,同時練習英文,希望這些帖子也能夠對大家有所幫助。 有 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...