設(shè)計(jì)者模式(1)觀察者模式(Observer)C++11實(shí)現(xiàn)-創(chuàng)新互聯(lián)

意圖

觀察者模式(Observer),又叫發(fā)布-訂閱模式(Publish/Subscribe),定義對(duì)象間一種一對(duì)多的依賴關(guān)系,使得每當(dāng)一個(gè)對(duì)象改變狀態(tài),則所有依賴于它的對(duì)象都會(huì)得到通知并自動(dòng)更新。
該模式屬于行為型模式。

創(chuàng)新互聯(lián)為您提適合企業(yè)的網(wǎng)站設(shè)計(jì)?讓您的網(wǎng)站在搜索引擎具有高度排名,讓您的網(wǎng)站具備超強(qiáng)的網(wǎng)絡(luò)競爭力!結(jié)合企業(yè)自身,進(jìn)行網(wǎng)站設(shè)計(jì)及把握,最后結(jié)合企業(yè)文化和具體宗旨等,才能創(chuàng)作出一份性化解決方案。從網(wǎng)站策劃到成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì), 我們的網(wǎng)頁設(shè)計(jì)師為您提供的解決方案。參與者
  • Subject:抽象主題(抽象被觀察者),抽象主題角色把所有觀察者對(duì)象保存在一個(gè)集合里,每個(gè)主題都可以有任意數(shù)量的觀察者,抽象主題提供一個(gè)或者多個(gè)接口,可以增加和刪除觀察者對(duì)象。
  • ConcreteSubject:具體主題(具體被觀察者),該角色將有關(guān)狀態(tài)存入具體觀察者對(duì)象,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),給所有注冊(cè)過的觀察者發(fā)送通知。
  • Observer:抽象觀察者,是觀察者者的抽象類,它定義了一個(gè)或者多個(gè)更新接口,使得在得到主題更改通知時(shí)更新自己。
  • ConcreteObserver:具體觀察者,實(shí)現(xiàn)抽象觀察者定義的更新接口,以便在得到主題更改通知時(shí)更新自身的狀態(tài)。
優(yōu)點(diǎn)
  • 觀察者模式可以實(shí)現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,抽象了更新接口,使得可以有各種各樣不同的表示層作為具體觀察者角色
  • 觀察者模式在觀察目標(biāo)和觀察者之間建立一個(gè)抽象的耦合
  • 觀察者模式支持廣播通信
缺點(diǎn)
  • 在應(yīng)用觀察者模式時(shí)需要考慮一下開發(fā)效率和運(yùn)行效率的問題,程序中包括一個(gè)被觀察者、多個(gè)觀察者,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。如果考慮到性能問題,可以實(shí)現(xiàn)一個(gè)異步非阻塞的觀察者模式,在每次fire subject的時(shí)候創(chuàng)建一個(gè)新的線程執(zhí)行代碼。

  • 觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。

代碼實(shí)現(xiàn)
#include#include#include#include#includeclass Observer;
typedef std::vector>::iterator Iterator;//迭代器

//抽象被觀察者
class Subject
{public:
    virtual void Attach(std::weak_ptr)=0;//注冊(cè)觀察者對(duì)象的接口
    virtual Iterator Detach(Iterator it)=0;//刪除觀察者對(duì)象的接口
    virtual void notifyObservers()=0;//告知所有觀察者update
};

//抽象觀察者

class Observer
{public:
    virtual void update()=0;//更新自身狀態(tài)
};

//被觀察者
class ConcreteSubject :public::Subject
{public:
    void Attach(std::weak_ptrs)
    {//vector的add是線程安全的
        observers_.push_back(s);
    }
    Iterator Detach(Iterator it)
    {//線程不安全,要在臨界區(qū)調(diào)用此接口
        return observers_.erase(it);
    }

    void notifyObservers()
    {lock.lock();
        Iterator it=observers_.begin();
        while(it!=observers_.end())
        {//先嘗試將weak_ptr提升為share_ptr
            std::shared_ptrobj=it->lock();
            if(obj)//提升成功,說明該對(duì)象未被其他線程析構(gòu)
            {obj->update();//更新
                ++it;
            }
            else//提升失敗,說明該對(duì)象已被其他線程析構(gòu)
            {//從觀察者集合中將已被析構(gòu)對(duì)象刪除
                //因?yàn)榇颂帉儆谂R界區(qū),是線程安全的
                it=Detach(it);
            }

        }
        lock.unlock();
    }
    
private:
    mutable std::mutex lock;
    std::vector>observers_;//觀察者集合

};

//觀察者按需求定義即可,需要繼承抽象觀察者
//以下為例
class Teacher :public::Observer
{public:
    void update()
    {std::cout<<"Teacher is update"<std::cout<<"Teacher is ~"<public:
    void update()
    {std::cout<<"Student is update"<std::cout<<"Student is ~"<

測試

int main()
{ConcreteSubject subject;
    
    std::shared_ptrteacher(new Teacher);
    subject.Attach(teacher);
    {std::shared_ptrstudent(new Student);
        subject.Attach(student);
        subject.notifyObservers();
    }


    subject.notifyObservers();

}

執(zhí)行結(jié)果

Teacher is update
Student is update
Student is ~
Teacher is update
Teacher is ~
迭代器失效問題分析

在學(xué)習(xí)該模型時(shí),遇到了一個(gè)bug,問題鎖定在notifyObservers()當(dāng)中,當(dāng)時(shí)的實(shí)現(xiàn)如下

void notifyObservers()
{lock.lock();
    Iterator it=observers_.begin();
    while(it!=observers_.end())
    {std::shared_ptrobj=it->lock();
        if(obj)
        {obj->update();
        }
        else
        {Detach(it);
        }
        it++;
    }
}

當(dāng)時(shí)執(zhí)行main時(shí),就會(huì)報(bào)段錯(cuò)誤,經(jīng)過檢查不難發(fā)現(xiàn),問題是迭代器失效了

刪除導(dǎo)致迭代器失效

這個(gè)問題其實(shí)很好分析,在一順序容器當(dāng)中(vector,queue…等),數(shù)據(jù)是順序存儲(chǔ)的,當(dāng)刪除一個(gè)元素后,內(nèi)存中的數(shù)據(jù)會(huì)往前移動(dòng),以保證數(shù)據(jù)的緊湊。所以刪除一個(gè)元素后,該元素后面的其他元素的地址都會(huì)發(fā)生改變。在刪除操作前所持有的迭代器就會(huì)有失效的可能??聪旅娴睦印?/p>

#include#include#includeusing namespace std;
int main()
{  vectorarr;
  arr.push_back(1);
  arr.push_back(2);
  arr.push_back(3);
  arr.push_back(4);
  arr.push_back(5);

  vector::iterator it=arr.begin()+3;

  cout<<"刪除操作前該迭代器所指向的元素:"<

執(zhí)行結(jié)果如下

刪除操作前該迭代器所指向的元素:
4
進(jìn)行刪除操作
刪除操作前該迭代器所指向的元素:
5
添加導(dǎo)致迭代器失效

你的添加的操作也是可能導(dǎo)致迭代器失效的。vector的容量是動(dòng)態(tài)的開辟的,當(dāng)容量不夠的話,會(huì)進(jìn)行realloc操作進(jìn)行擴(kuò)容,若該數(shù)組的后面的空間不足,realloc函數(shù)會(huì)找一片更大的空間,將原數(shù)據(jù)拷貝進(jìn)去。若在此事件發(fā)生前,獲取一個(gè)迭代器,此事件發(fā)生后,該迭代器會(huì)失效。看下面例子

#include#include#includeusing namespace std;
int main()
{  vectorarr;
  arr.push_back(1);
  arr.push_back(2);
  arr.push_back(3);
  arr.push_back(4);
  arr.push_back(5);

  vector::iterator it=arr.begin()+3;

  cout<<"此事件發(fā)生前該迭代器所指向的元素:"<arr.push_back(9);
  }
  cout<<"此事件發(fā)生后該迭代器所指向的元素:"<

執(zhí)行結(jié)果

此事件發(fā)生前該迭代器所指向的元素:
4
此事件發(fā)生后該迭代器所指向的元素:
21854

此時(shí)該迭代器就指向一個(gè)未初始化的空間

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

當(dāng)前標(biāo)題:設(shè)計(jì)者模式(1)觀察者模式(Observer)C++11實(shí)現(xiàn)-創(chuàng)新互聯(lián)
文章位置:http://bm7419.com/article26/djhccg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、商城網(wǎng)站、App設(shè)計(jì)標(biāo)簽優(yōu)化、手機(jī)網(wǎng)站建設(shè)ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)