Observer(觀察者)-對象行為型模式

来源:http://www.cnblogs.com/mgp200866130/archive/2016/07/31/5723088.html
-Advertisement-
Play Games

1.意圖 定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。 2.別名 依賴(Depenents),發佈-訂閱(Publish-subscribe) 3.動機 一個目標可以有任意數目的依賴它的觀察者。一旦目標的狀態發生改變,所有的觀察者都得到通知 ...


1.意圖

    定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

2.別名

    依賴(Depenents),發佈-訂閱(Publish-subscribe)

3.動機

    一個目標可以有任意數目的依賴它的觀察者。一旦目標的狀態發生改變,所有的觀察者都得到通知。作為這個通知的響應,每個觀察者都將查詢目標以使其狀態於目標的同步。

4.適用性

  • 當一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這二者封裝在獨立的對象中以使它們可以各自獨立改變和復用。
  • 當一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變。
  • 當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之,你不希望這些對象是緊耦合的。

5.結構

    

6.代碼實例

//Subject.h

#include <memory>
#include <vector>

class AbstractObserver;

class AbstractSubject
{
public:
    virtual void Attach(std::shared_ptr<AbstractObserver> pObserber)=0;
    virtual void Notify()=0;
    virtual void SetState(int state)=0;
    virtual int GetState()=0;
};

class ConcreteSubject : public AbstractSubject
{
public:
    ConcreteSubject();
    ~ConcreteSubject();
    virtual void Attach(std::shared_ptr<AbstractObserver> pObserber);
    virtual void Notify();
    virtual void SetState(int state);
    virtual int GetState();
private:
    std::vector<std::shared_ptr<AbstractObserver>> m_vecObservers;
    int m_state;
};
//Observer.h

#include <memory>

class AbstractSubject;

class AbstractObserver
{
public:
    virtual void Update()=0;
};

class ConcreteObserver1 : public AbstractObserver
{
public:
    ConcreteObserver1(std::shared_ptr<AbstractSubject> pSubject);
    ~ConcreteObserver1();
    virtual void Update();
private:
    std::shared_ptr<AbstractSubject> m_Subject;
};

class ConcreteObserver2: public AbstractObserver
{
public:
    ConcreteObserver2(std::shared_ptr<AbstractSubject> pSubject);
    ~ConcreteObserver2();
    virtual void Update();
private:
    std::shared_ptr<AbstractSubject> m_Subject;
};

class ConcreteObserver3 : public AbstractObserver
{
public:
    ConcreteObserver3(std::shared_ptr<AbstractSubject> pSubject);
    ~ConcreteObserver3();
    virtual void Update();
private:
    std::shared_ptr<AbstractSubject> m_Subject;
};
//Subject.cpp

#include "Subject.h"
#include "Observer.h"

ConcreteSubject::ConcreteSubject()
{
}

ConcreteSubject::~ConcreteSubject()
{
}

void ConcreteSubject::SetState(int state)
{
    m_state = state;
}

void ConcreteSubject::Attach(std::shared_ptr<AbstractObserver> pObserver)
{
    m_vecObservers.push_back(pObserver);
}

int ConcreteSubject::GetState()
{
    return m_state;
}

void ConcreteSubject::Notify()
{
    for(auto iter = m_vecObservers.begin(); iter != m_vecObservers.end(); ++iter)
    {
        (*iter)->Update();
    }
}
// Observer.cpp


#include "Observer.h"
#include "Subject.h"
#include <iostream>

ConcreteObserver1::ConcreteObserver1(std::shared_ptr<AbstractSubject> pSubject)
    : m_Subject(pSubject)
{
}

ConcreteObserver1::~ConcreteObserver1()
{
}

void ConcreteObserver1::Update()
{
    std::cout << "ConcreteObserver1 Updated state:" << m_Subject->GetState() << std::endl;
}


ConcreteObserver2::ConcreteObserver2(std::shared_ptr<AbstractSubject> pSubject)
    : m_Subject(pSubject)
{
}

ConcreteObserver2::~ConcreteObserver2()
{
}

void ConcreteObserver2::Update()
{
    std::cout << "ConcreteObserver2 Updated state:" << m_Subject->GetState() << std::endl;
}


ConcreteObserver3::ConcreteObserver3(std::shared_ptr<AbstractSubject> pSubject)
    : m_Subject(pSubject)
{
}

ConcreteObserver3::~ConcreteObserver3()
{
}

void ConcreteObserver3::Update()
{
    std::cout << "ConcreteObserver3 Updated state:" << m_Subject->GetState() << std::endl;
}
//client.cpp

#include "Observer.h"
#include "Subject.h"


int main()
{
    std::shared_ptr<AbstractSubject> pSubject(new ConcreteSubject);
    
    std::shared_ptr<AbstractObserver> pObserver1(new ConcreteObserver1(pSubject));
    std::shared_ptr<AbstractObserver> pObserver2(new ConcreteObserver2(pSubject));
    std::shared_ptr<AbstractObserver> pObserver3(new ConcreteObserver3(pSubject));

    pSubject->Attach(pObserver1);
    pSubject->Attach(pObserver2);
    pSubject->Attach(pObserver3);

    pSubject->SetState(5);

    pSubject->Notify();

    while(1);
}

7.測試結果

    

8.效果

  • 目標和觀察者間的抽象耦合
  • 支持廣播通信
  • 意外的更新 因為一個觀察者並不知道其它觀察者的存在,它可能對改變目標的最終代價一無所知。在目標上一個看似無害的操作可能會引起一系列對觀察者以及依賴於這些觀察者的那些對象的更新。此外,如果依賴準則的定義或維護不當,常常會引起錯誤的更新,這種錯誤通常難以捕捉。

 


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

-Advertisement-
Play Games
更多相關文章
  • 題意是將一串數字轉換成另一種形式。比如5553141轉換成2個1,1個3,1個4,3個5,即21131435。1000000000000轉換成12011。數字的個數是可能超過9個的。n個m,m是從小到大排序。 輸出的結果又四種情況,建議判斷的時候就按照題目的順序進行判斷,否則可能出錯。第一種情況是進 ...
  • 題目鏈接:http://acm.nyist.net/JudgeOnline/problem.php?pid=860 My思路: 先用兩個字元串儲存這兩個實數,然後再用另外兩個字元串儲存去掉符號和前後多餘的0後的新"實數",最後只需要比較兩個化簡後的新字元就ok了。 My代碼實現: 1 #includ ...
  • 用php進行靜態類型編程,估計是我的一個心結。 依次有幾篇文章都記錄了我的一些探索: 通過指定函數/方法形參類型提高PHP代碼可靠性 http://www.cnblogs.com/x3d/p/4285787.html 用Yii框架中的collections體驗PHP類型化編程 http://www. ...
  • 一、Get/Load Get方法是立即檢索,而load是延遲檢索,他們都是根據主鍵進行查詢。在<class>標簽中,若把lazy屬性改為false,load方法就會立即檢索,class中的lazy屬性僅對load方法有效。在使用load時,當資料庫沒有找到數據時,會有ObjectNotFoundEx ...
  • 理想的情況下,一個 Java 程式使用 JVM 的預設設置也可以運行得很好,所以一般來說,沒有必要設置任何 JVM 參數。然而,由於一些性能問題(很不幸的是,這些問題經常出現),一些相關的 JVM 參數知識會是我們工作中得好伙伴。在這篇文章中,我們將介紹一些關於 JVM 記憶體管理的參數。知道並理解這 ...
  • 問題描述: 輸入一組整數,求出這組數字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那個序列。例如: 序列:-2 11 -4 13 -5 -2,則最大子序列和為20。 序列:-6 2 4 -7 5 3 2 -1 6 -9 10 -2,則最大子序列和為16。 O(n)解法: ...
  • Zend\Mvc\MvcEvent繼承自Zend\EventManager\Event,在Zend\Mvc\Application::bootstrap()執行時觸發。如果你的控制器實現了Zend\Mvc\InjectApplicationEventInterface,MvcEvent將會被註入到這 ...
  • Schema約束 俗話說得好 好記性不如爛筆頭。 看了下WebService視頻,覺得還是得下筆記。 觀看的視頻地址:http://edu.51cto.com/lesson/id-25757.html 複習下xml約束 bool.xsd是book.xml的約束文檔 schema規範中: 1. 所有標 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...