首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

設計模式實作系列(十五):Observer 觀察者模式 - 發布訂閱機制實現物件鬆耦合聯動

     編輯:關於C++

模式意圖

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

UML 結構圖

Observer Pattern UML

核心解析

  • Subject(主題): 維護觀察者容器(std::list<Observer*>),提供 Attach/Detach/Notify 介面。
  • Observer(觀察者): 抽象基類定義 Update(Subject*),具體觀察者實作更新邏輯。
  • 解耦關鍵: Subject 僅持有 Observer*,不知曉具體觀察者型別;觀察者透過 Subject::GetState() 取得新狀態。
  • 推/拉模型: 推模型在 Notify 時直接傳遞資料;拉模型讓觀察者主動向 Subject 索取。本實作採拉模型,彈性較高。

C++ 完整實作

1. Observer.h

#ifndef OBSERVER_H
#define OBSERVER_H

#include <list>
typedef int STATE;

class Observer;
class Subject {
public:
    Subject() : m_nSubjectState(-1) {}
    virtual ~Subject();
    void Notify();
    void Attach(Observer* pObserver);
    void Detach(Observer* pObserver);
    virtual void SetState(STATE nState);
    virtual STATE GetState();
protected:
    STATE m_nSubjectState;
    std::list<Observer*> m_ListObserver;
};

class Observer {
public:
    Observer() : m_nObserverState(-1) {}
    virtual ~Observer() {}
    virtual void Update(Subject* pSubject) = 0;
protected:
    STATE m_nObserverState;
};

class ConcreteSubject : public Subject {
public:
    ConcreteSubject() : Subject() {}
    virtual ~ConcreteSubject() {}
    virtual void SetState(STATE nState);
    virtual STATE GetState();
};

class ConcreteObserver : public Observer {
public:
    ConcreteObserver() : Observer() {}
    virtual ~ConcreteObserver() {}
    virtual void Update(Subject* pSubject);
};

#endif

2. Observer.cpp

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

void Subject::Attach(Observer* pObserver) {
    std::cout << "Attach an Observer\n";
    m_ListObserver.push_back(pObserver);
}
void Subject::Detach(Observer* pObserver) {
    auto iter = std::find(m_ListObserver.begin(), m_ListObserver.end(), pObserver);
    if (iter != m_ListObserver.end()) m_ListObserver.erase(iter);
    std::cout << "Detach an Observer\n";
}
void Subject::Notify() {
    std::cout << "Notify Observers's State\n";
    for (auto pObs : m_ListObserver) pObs->Update(this);
}
void Subject::SetState(STATE nState) {
    std::cout << "SetState By Subject\n"; m_nSubjectState = nState;
}
STATE Subject::GetState() {
    std::cout << "GetState By Subject\n"; return m_nSubjectState;
}
Subject::~Subject() {
    for (auto pObs : m_ListObserver) delete pObs;
    m_ListObserver.clear();
}

void ConcreteSubject::SetState(STATE nState) {
    std::cout << "SetState By ConcreteSubject\n"; m_nSubjectState = nState;
}
STATE ConcreteSubject::GetState() {
    std::cout << "GetState By ConcreteSubject\n"; return m_nSubjectState;
}

void ConcreteObserver::Update(Subject* pSubject) {
    if (!pSubject) return;
    m_nObserverState = pSubject->GetState();
    std::cout << "The ObserverState is " << m_nObserverState << std::endl;
}

3. Main.cpp

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

int main() {
    Observer* p1 = new ConcreteObserver;
    Observer* p2 = new ConcreteObserver;
    Subject* p = new ConcreteSubject;
    p->Attach(p1); p->Attach(p2);
    p->SetState(4); p->Notify(); // 兩觀察者皆更新為 4
    p->Detach(p1);
    p->SetState(10); p->Notify(); // 僅 p2 更新為 10
    delete p;
    return 0;
}

現代 C++ 與實務考量

  • 智慧指標: 使用 std::shared_ptr<Observer> / std::weak_ptr 管理生命週期,避免記憶體洩漏與懸空指標。
  • 執行緒安全: 多執行緒環境下需鎖保護觀察者容器(std::mutex)。
  • 標準庫替代: C++20 std::observable(實驗性)、Boost.Signals2、Qt Signals/Slots 提供更完善的訊號槽機制。

適用場景

  • GUI 事件處理(按鈕點擊通知多個監聽器)。
  • 資料模型變更通知多個視圖(MVC 架構)。
  • 訊息總線、事件驅動架構、股價監控、日誌系統。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved