1. 程式人生 > >觀察者模式的程式例項C++ 以及觀察者模式與事件監聽的區別

觀察者模式的程式例項C++ 以及觀察者模式與事件監聽的區別

一、什麼是觀察者模式      Observer模式也叫觀察者模式,它的作用是當一個物件的狀態發生變化時,可以自己主動通知其它關聯物件,自己主動重新整理物件狀態。

舉個樣例,使用者介面能夠作為一個觀察者,業務資料是被觀察者,使用者介面觀察業務資料的變化,發現數據變化後,就顯示在介面上。觀察者模式在模組之間劃定了清晰的界限,提高了應用程式的可維護性和重用性。

“觀察”不是“直接呼叫” 實現觀察者模式的時候要注意,觀察者和被觀察物件之間的互動關係不能體現成類之間的直接呼叫,否則就將使觀察者和被觀察物件之間緊密的耦合起來,從根本上違反面向物件的設計的原則。不管是觀察者“觀察”物件,還是被觀察者將自己的改變“通知”觀察者,都不應該直接呼叫。

實現觀察者模式的形式

實現觀察者模式有非常多形式,比較直觀的一種是使用一種“註冊——通知——撤銷註冊”的形式。

   實現觀察者模式樣例

       以下是C++的實現,在C++實現中,C++中沒有介面的概念,可是能夠用抽象類類取代Java或C#中的介面,在C++中抽象類中從派生類中抽象出來的函式(方法),必須定義成純虛擬函式,這樣在後面的使用中才幹夠通過基類的指標來訪問這些函式,面向物件的語言中有個特點,多型僅僅能訪問兩者中共同擁有的部分。

#include <iostream>
#include <list>
#include <string>
using namespace std;

class Observer;
class Subject
{
public:
    virtual void attach(Observer *o) = 0;
    virtual void change() = 0;
    virtual void setWeather(string str) = 0;
    virtual string getWeather() = 0;
};
class Observer
{
public:
    virtual string getName() = 0;
    virtual void update(Subject *s) = 0;
};

class Earth: public Subject
{
private:
    string weather;
    list<Observer * > *l; //指標
public:
    Earth()
    {
        l = new list<Observer *>;
    }
    void attach(Observer *o)
    {
        this->l->push_back(o);
    };
    void change()
    {
        for(list<Observer *>::iterator it = l->begin(); it != l->end(); ++it)
        {
            (*it)->update(this);
        }
    };
    void setWeather(string str)
    {
        this->weather = str;
        change();
    };
    string getWeather()
    {
        return this->weather;
    };
};
class Satellite: public Observer
{
private:
    string name;
public:
    Satellite(string str)
    {
        name = str;
    }
    string getName()
    {
        return name;
    };
    void update(Subject *s)
    {
        cout << this->getName() + " " + s->getWeather();
    }
};




int main()
{
    Earth e;
    Satellite *s1 = new Satellite("風雲一號");
    Satellite *s2 = new Satellite("風雲二號");
    Satellite *s3 = new Satellite("風雲三號");
    Satellite *s4 = new Satellite("風雲四號");
    e.attach(s1);
    e.attach(s2);
    e.attach(s3);
    e.attach(s4);
    e.setWeather("fine");



    while(1) {}
    return 0;
}

觀察者模式和事件監聽模式的區別

說到事件監聽模式,很容易將它和觀察者模式聯絡在一起。 實質上這兩者完成同類型的工作。依個人理解,事件監聽模式更像是觀察者模式的進階。   用一張圖來方便描述它們的區別:

觀察者模式中,‘主題’會在特定邏輯下通知所有‘觀察者’。 如果這個通知不包含任何資訊,那麼這種實現就是通常的觀察者模式。

    class Subject
    {
    protected:
        void notify()
        {
            for (int i = 0; i < numObservers_; i++)
            {
              observers_[i]->onNotify();
            }
        }
    };

如果‘主題’通知‘觀察者’的過程帶有一些<其他資訊>。那麼‘主題’本身已經上升成為了‘事件源’, 而通知中帶有的<其他資訊>經過封裝就成為了事件。  

    class Subject
    {
    protected:
        void notify(const Entity& entity, Event event)
        {
            for (int i = 0; i < numObservers_; i++)
            {
              observers_[i]->onNotify(entity, event);
            }
        }
    };

事件監聽模式的優勢: 在很多應用場景中,通知中附帶的<其他資訊>是必不可少的, 事件Event則對這些<資訊>進行了封裝,使它本身擁有了多型的特性。 每個事件物件就可以包含不同的資訊。但各個‘觀察者’提供給‘主題’的介面仍然是統一的 : onNotify(entity, event)

舉個簡單的例子,某遊戲中的成就係統包含兩種成就: 1.達成等級成就(觀察者1)    2.達成戰鬥力成就(觀察者2) 玩家(事件源)在完成升級時會建立兩個物件, 升級事件(包含玩家等級欄位)     戰鬥力提升事件(包含玩家當前戰鬥力欄位)。 成就係統收到事件後執行統一的邏輯: observers_[event.type]->OnAchieveEvent(entity, event);   總結來說 事件監聽機制就是對觀察者模式進行了進一步抽象,節省了程式碼量。 --------------------- 作者:AXuanK 來源:CSDN 原文:https://blog.csdn.net/AXuan_K/article/details/78803382 版權宣告:本文為博主原創文章,轉載請附上博文連結!