觀察者設計模式–學習筆記

來源:互聯網
上載者:User

 

意圖:

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

 

 

適用環境:

1)       當一個抽象模型有兩個方面, 其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。

2)       當對一個對象的改變需要同時改變其它對象, 而不知道具體有多少對象有待改變。

3)         當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不希望這些對象是緊密耦合的。

 

結構:

Observer的對象作為Subject的成員,然後通過observers調用Update函數,其實調用的是ConcreteObserver的Update()函數,這正是C++中的多態的體現:基類指標調用衍生類別的函數;

        

         同樣在ConcreteObserver中儲存對ConCreteSubject的引用,這樣通過subject就可以訪問到ConcreteSubject中的GetState函數,這樣Subject和Observer就可以相互訪問了。注意不能定義Subject指標指向ConcreteSubject的對象,因為此時不能通過基類的指標訪問ConcreteSubjec的GetState函數,因為基類中沒有這個函數;

 

   同時在Subject類中通過List鏈表儲存觀察者,通過使用迭代器遍曆鏈表;實現所有的觀察者狀態的更新;

 

 

協作關係:

當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者。

在得到一個具體目標的改變通知後,ConcreteObserver對象可向目標物件查詢資訊,ConcreteObserver使用這些資訊以使它的狀態與目標對象的狀態保持一致;

發生改變請求的Observer對象並不立即更新,而是將其延遲到它從目標得到一個通知之後。

Notify 可以由目標對象(subject)觸發,也可以由使用者觸發;

 

 

程式源碼:

BaseSubject.h

#pragma once
#include "BaseObserver.h"
#include <list>
using namespace std;

class BaseSubject
{
public:

 BaseSubject(void);
 virtual ~BaseSubject(void);
 /*
 */
 virtual void Attach(BaseObserver*);
 virtual void Detach(BaseObserver*);
 virtual void Notify();

private:
 list<BaseObserver*> *_observers;
};

 

BaseSubject.cpp 檔案

 

#include "StdAfx.h"

#include "BaseSubject.h"

BaseSubject::BaseSubject(void)
{

}

BaseSubject::~BaseSubject(void)
{
}

void BaseSubject::Attach (BaseObserver *o) {
 _observers->push_back(o);
}

/*
*/
void BaseSubject::Detach (BaseObserver* o) {
 list<BaseObserver*>::iterator iter;
 for (iter=_observers->begin();iter!=_observers->end();iter++)
 {
  if ((*iter)==o)
  {
   _observers->erase(iter++);

  }else
  {
   iter++;
  }
 }
}
/*
*/
void BaseSubject::Notify () {
 //
 list<BaseObserver*>::iterator iter;

 for (iter=_observers->begin();iter!=_observers->end();iter++)
 {
  (*iter)->Update();
 }

}

 

DerivedSubject.h檔案

#pragma once

class DerivedSubject
{
public:
 DerivedSubject(void);
 virtual ~DerivedSubject(void);

 int GetState();
 void SetState(int i);
 int SubjectState;
};

 

DerivedSubject.cpp 檔案

#include "StdAfx.h"
#include "DerivedSubject.h"

DerivedSubject::DerivedSubject(void)
{
}

DerivedSubject::~DerivedSubject(void)
{
}

int DerivedSubject::GetState()
{
 return SubjectState;
}

void DerivedSubject::SetState(int i)
{
 SubjectState=i;
}

 

BaseObserver.h檔案

#pragma once

class BaseObserver
{
public:
 BaseObserver(void);

 BaseObserver(const BaseObserver&pt)
 {
  printf("");
 }
 
 virtual ~BaseObserver(void);
 virtual void Update() = 0;
};

 

BaseObserver.cpp 檔案

#include "StdAfx.h"
#include "BaseObserver.h"

BaseObserver::BaseObserver(void)
{
}

BaseObserver::~BaseObserver(void)
{
}

 

DerivedObserver.h 檔案

#pragma once
#include "baseobserver.h"
#include "DerivedSubject.h"

class DerivedObserver :
 public BaseObserver
{
public:
 DerivedObserver(void);
 virtual ~DerivedObserver(void);

 void Update();
private:
 int ObserverState;
 DerivedSubject subject;
};

 

DerivedObserver.cpp 檔案

#include "StdAfx.h"
#include "DerivedObserver.h"

DerivedObserver::DerivedObserver(void)
{
}

DerivedObserver::~DerivedObserver(void)
{
}

void DerivedObserver::Update()
{
 ObserverState=subject.GetState();
 printf("ObserverState%d\n",ObserverState);
}

 

 調用主函數:

// ObserverPattern.cpp : 定義控制台應用程式的進入點。
//

#include "stdafx.h"
#include "BaseSubject.h"
#include "DerivedSubject.h"
#include "BaseObserver.h"
#include "DerivedObserver.h"

int _tmain(int argc, _TCHAR* argv[])
{
 
 BaseSubject *m_Subject=new BaseSubject();
 DerivedSubject *m_ConcreteSubject=new DerivedSubject();
 BaseObserver *m_Observer=new DerivedObserver();

 m_ConcreteSubject->SetState(2);
 printf("SubjectState%d\n",m_ConcreteSubject->SubjectState);

 m_Subject->Attach(m_Observer);
 m_Subject->Notify();

 return 0;
}

 

 程式中需要注意的問題引申:

1)vector順序容器,List順序容器,Map關聯容器的erase失效情況?

順序容器和關聯容器erase元素,注意:

vector順序容器erase元素後,不僅使所有指向被刪元素的迭代器失效,而且使被刪元素之後的所有迭代器失效,所以不能使用erase(iter++)的方法;

正確的用法:

for(iter=c.begin();iter!=c.end();)

{

    iter=c.erase(iter);//erase 返回下一個有效迭代器;

}

 

關聯容器map: erase迭代器只是被刪元素的迭代器失效,但傳回值為void;所以要採用erase(iter++)的方式刪除迭代器;

 

for(iter=c.begin();iter!=c.end())

{

        c.erase(iter++);

}

對應map

 

for(map<int ,string>::iterator iter=strmap.begin();iter!=strmap.end())

{

    if(some_condition)

     {

     strmap.erase(iter++);

    }else

    {

     iter++;

    }

}

 

list erase只使得當前的節點失效,處理方法和map類似;

2)在程式中push_back出現記憶體衝突,我沒有仔細去檢查問題,哪位解決了,也麻煩告訴我下,謝謝!

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.