Head First Design Patterns學習筆記-觀察者模式

来源:http://www.cnblogs.com/pppploi8/archive/2016/07/10/5658008.html
-Advertisement-
Play Games

認識觀察者模式 首先來看看報紙訂閱的過程 1.報社的業務就是出版報紙 2.向某家報社訂閱報紙,只要他們有新報紙出版,就會送過來,只要你是他們的訂戶 3.當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙 4.只要報社還在運營,就會一直有人來訂閱或取消訂閱報紙 觀察者模式和報紙訂閱流程是一樣的,只 ...


認識觀察者模式

首先來看看報紙訂閱的過程

  • 1.報社的業務就是出版報紙
  • 2.向某家報社訂閱報紙,只要他們有新報紙出版,就會送過來,只要你是他們的訂戶
  • 3.當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙
  • 4.只要報社還在運營,就會一直有人來訂閱或取消訂閱報紙

觀察者模式和報紙訂閱流程是一樣的,只是名字不同。出版社改名為主題(Subject),而訂閱者改名為觀察者(Observer)

觀察者模式的定義

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

觀察者模式代碼

//主題介面
interface Subject {
    void registerObserver(Observer o);//增加觀察者
    void removeObserver(Observer o);//刪除觀察者
    void notifyObservers();//當主題狀態改變時,調用此方法通知所有觀察者
}
//觀察者介面
interface Observer {
    void update(float temp); //用來接收主題發送的通知,這裡假設主題是溫度計,通過介面給觀察者發送當前溫度
}
//主題實現
class Thermometer implements Subject {
    private List<Observer> observers = new ArrayList<>();//觀察者集合
    private float temp = 0.0f;//溫度
    public void setTemp(float temp) {//溫度更新
        this.temp = temp;
        notifyObservers();
    }
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    @Override
    public void removeObserver(Observer o) {
        if (observers.indexOf(o) >= 0)
            observers.remove(o);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temp);
        }
    }
}
//觀察者實現
class ObserverA implements Observer {
    @Override
    public void update(float temp) {
        System.out.println("觀察者A:當前的溫度是" + temp);
    }
}
class ObserverB implements Observer {
    @Override
    public void update(float temp) {
        System.out.println("觀察者B:當前的溫度是" + temp);
    }
}
public class JavaApplication {
    public static void main(String[] args) throws Exception{
       //具體使用
       Thermometer t = new Thermometer();
       Observer a = new ObserverA();
       Observer b = new ObserverB();
       //為a,b註冊成為ts的觀察者
       t.registerObserver(a);
       t.registerObserver(b);
       //更新溫度
       t.setTemp(23.00f);
       //a不再當觀察者
       t.removeObserver(a);
       //更新溫度
       t.setTemp(24.00f);
    }
}

另外,Java中已經內置了觀察者模式,在java.util包下有Observer介面和Observable類

和這裡的Subject介面和Observer介面很相似,修改後的代碼如下

//主題實現
class Thermometer extends Observable{
    private float temp = 0.0f;//溫度
    public void setTemp(float temp) {//溫度更新
        this.temp = temp;
        setChanged();//說明狀態已改變
        notifyObservers(temp);
    }
}
//觀察者實現
class ObserverA implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("觀察者A:當前的溫度是" + arg);
    }
}
class ObserverB implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("觀察者B:當前的溫度是" + arg);
    }
}
public class JavaApplication {
    public static void main(String[] args) throws Exception{
       //具體使用
       Thermometer t = new Thermometer();
       Observer a = new ObserverA();
       Observer b = new ObserverB();
       //為a,b註冊成為ts的觀察者
       t.addObserver(a);
       t.addObserver(b);
       //更新溫度
       t.setTemp(23.00f);
       //a不再當觀察者
       t.deleteObserver(a);
       //更新溫度
       t.setTemp(24.00f);
    }
}

另外,既然JDK是開源的,那麼就順便去看看JDK的源碼中的具體實現

(這裡使用的源碼版本為jdk1.8.0_74)

Observable對象:(大部分沒什麼區別的代碼就不放出來了)

public Class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;
    
    ...
}

私有成員變數,一個是標誌,用於後續判斷是否通知觀察者,一個觀察者集合obs,使用的是Vector容器

標誌的用途是用於增加自由度,比如說一秒鐘更新10次數據,對於前臺顯示而言可能不需要這麼頻繁,那麼我們可以自己計數,如果達到10次才設置標誌

可以在通知觀察者方法源碼里看到changed的作用

public void notifyObservers(Object arg) {
    Object[] arrLocal;
    synchronized (this) {
        if (!changed)
            return;
        arrLocal = obs.toArray();
        clearChanged();//clearChanged方法里的具體代碼就一句:changed = false;
    }
    for (int i = arrLocal.length-1; i>=0; i--)
        ((Observer)arrLocal[i]).update(this, arg);
}

而Observer介面更是沒什麼好說的

public interface Observer {
    void update(Observable o, Object arg);
}

相對於我們自己實現的觀察者模式,主要區別在於將ArrayList換成了Vector,方法都加上了synchronized關鍵字來保證線程安全,並沒有什麼特別的← ←


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

-Advertisement-
Play Games
更多相關文章
  • R語言在Linux下安裝一不小心就容易出錯,本文給出了Ubuntu 16.04LTS版本下的R和RStudio Server的安裝方法,不需要自己下載相關包,方便,快捷! ...
  • python-super 由Python的super()函數想到的 首先看一下super()函數的定義: 返回一個代理對象, 這個對象負責將方法調用分配給第一個參數的一個父類或者同輩的類去完成. parent or sibling class 如何確定? 第一個參數的__mro__屬性決定了搜索的順 ...
  • 程式流程式控制制 順序結構 分支結構:if else,switch case 迴圈結構:while,do while,for if else三種格式 //列印九九乘法表 for(int i = 1;i 費時太多,需要優化,首先在flag底下加break,然後將flag==false改為!flag,再將j ...
  • 關鍵字 定義:被java語言賦予了特殊含義,用作專門用途的字元串。 特點:關鍵字所有字母都小寫。 保留字 現有java版本尚未使用,但以後版本會作為關鍵字使用.byValue,cast,future,inner,outer,var,goto,const 標示符 java對各種 變數 , 方法和類 等 ...
  • Google一下輕鬆找到了答案,大家可以看一下 "Python Wiki" ,很簡單,翻譯如下。 在Python中,當你使用a[key]這種方式從字典中獲取一個值時,若字典中不存在這個此key時就會產生一個KeyError的錯誤,比如: 不過也提供瞭解決辦法:可以使用a.get(key, defau ...
  • 框架開源後,學習使用的人越來越多了,所以我也更加積極的用代碼回應了。在框架完成了:資料庫讀寫分離功能 和 分散式緩存功能 後:經過三天三夜的不眠不休,終於完成框架第三個重量級的功能:自動化分散式緩存。源代碼已經提交,源碼地址見:終於等到你:CYQ.Data V5系列 (ORM數據層)最新版本開源了 ...
  • 最近打算用C#實現一個基於文件的EventStore。 什麼是EventStore 關於什麼是EventStore,如果還不清楚的朋友可以去瞭解下CQRS/Event Sourcing這種架構,我博客中也有大量介紹。EventStore是在Event Sourcing(下麵簡稱ES)模式中,用於存儲 ...
  • ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...