设计模式C++描述----04.观察者(Observer)模式
来源:互联网 发布:尔雅网络课程注册网址 编辑:程序博客网 时间:2024/06/04 19:01
一. 概述
Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。
Sbuject 相当于通知者,它提供依赖于它的观察者Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。
Observer 相当于观察者,则提供一个Update操作,注意这里的 Observer 的 Update 操作并不在Observer 改变了Subject目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有 Observer 进行修改(调用Update)。
二. 举例
最常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。
结构关系图如下:
DataSubject : 我们就认为是原始数据。
SheetObserver:就认为是表格,用来显示原始数据用的。
ChartObserver :就认为是图表,也是来显示原始数据的。
代码如下:
////////////////////////////////////////////////////////////////////////////观察者基类class Observer{public:virtual ~Observer(){}virtual void Update(Subject* sub) = 0;virtual void PrintInfo() = 0;protected:Observer(){_st = '\0';}string _st;};////////////////////////////////////////////////////////////////////////// //通知者基类 class Subject{public:virtual ~Subject(){}//注册观察者,这样通知者就能通知到观察者virtual void Attach(Observer* obv){_obvs->push_front(obv);}//注销观察者,通知者不再通知观察者virtual void Detach(Observer* obv){if (obv != NULL)_obvs->remove(obv);}//通知操作,通知后对于每个注册过的观察者,将会调用自己的update方法virtual void Notify(){list<Observer*>::iterator it;it = _obvs->begin();for (;it != _obvs->end();it++){(*it)->Update(this);}}virtual void SetState(const string& st) = 0;virtual string GetState() = 0;protected:Subject(){_obvs = new list<Observer*>;}private:list<Observer* >* _obvs;};////////////////////////////////////////////////////////////////////////////具体的数据通知者class DataSubject:public Subject{public:DataSubject(){_st = '\0';}~DataSubject(){} //自己的状态string GetState(){return _st;}void SetState(const string& st){_st = st;}private:string _st;};////////////////////////////////////////////////////////////////////////////数据表格观察者class SheetObserver:public Observer{public:virtual Subject* GetSubject(){return _sub;} //构造函数里,把自己注册到通知者里SheetObserver(Subject* sub){_sub = sub;_sub->Attach(this);}virtual ~SheetObserver(){_sub->Detach(this);if (_sub != 0)delete _sub;}//更新操作void Update(Subject* sub){_st = sub->GetState(); //具体的数据可以从Subject这个通知者中取PrintInfo();}void PrintInfo(){cout<<"Sheet observer.... "<<_sub->GetState()<<endl;}private:Subject* _sub;};//数据图表观察者class ChatObserver:public Observer{public:virtual Subject* GetSubject(){return _sub;}ChatObserver(Subject* sub){_sub = sub;_sub->Attach(this);}virtual ~ChatObserver(){_sub->Detach(this);if (_sub != 0){delete _sub;}}//更新操作 void Update(Subject* sub){_st = sub->GetState();PrintInfo();}void PrintInfo(){cout<<"Chat observer.... "<<_sub->GetState()<<endl;}private:Subject* _sub;};////////////////////////////////////////////////////////////////////////////测试 int main() { DataSubject* sub = new DataSubject();//数据通知者Observer* o1 = new SheetObserver(sub);//表格观察者 Observer* o2 = new ChatObserver(sub);//图表观察者 sub->SetState("old data");//数据发生变化sub->Notify();//通知者下发通知 sub->SetState("new data");sub->Notify();o1->Update(sub); //也可以由观察者自己调用更新函数 return 0;}说明:
1. 在 Observer 模式的实现中,Subject 维护一个 list 作为存储其所有观察者的容器。每当调用 Notify 操作就遍历 list中的 Observer 对象,并广播通知改变状态(调用Observer的Update操作)。
2. 运行示例程序,可以看到当原始数据 Subject 处于状态 “old” 时候,依赖于它的两个观察者都显示 “old”,当原始数据状态改变为 “new” 的时候,依赖于它的两个观察者也都改变为“new”。
3. 可以看到 Observer 与 Subject 互为耦合,但是这种耦合的双方都依赖于抽象,而不依赖于具体。
三. MFC中的观察者模式
MFC 的 View/Document 结构的实现中也采用了观察者模式。
Document 为模式中的通知者,管理应用程序中的数据,View为模式中的观察者,以给定的方显示所关联的 Document中的数据。CDocument类中定义了一个指针列表,用于保存对应的 CView 对象,并定义了一个函数用于对链表中的所有CView的对象进行更新。
结构如下:
原代码如下:
//afxwin.hclass CDocument : public CCmdTarget{public:// Operationsvoid AddView(CView* pView); //注册操作void RemoveView(CView* pView); //注销操作// Update Views (simple update - DAG only) //通知操作void UpdateAllViews(CView* pSender, LPARAM lHint = 0L,CObject* pHint = NULL);protected:CPtrList m_viewList; // list of views}//DocCore.cppvoid CDocument::AddView(CView* pView){ASSERT_VALID(pView);ASSERT(pView->m_pDocument == NULL); // must not be already attachedASSERT(m_viewList.Find(pView, NULL) == NULL); // must not be in listm_viewList.AddTail(pView); //加入链表中ASSERT(pView->m_pDocument == NULL); // must be un-attachedpView->m_pDocument = this;OnChangedViewList(); // must be the last thing done to the document}void CDocument::RemoveView(CView* pView){ASSERT_VALID(pView);ASSERT(pView->m_pDocument == this); // must be attached to usm_viewList.RemoveAt(m_viewList.Find(pView)); //从链表中删除pView->m_pDocument = NULL;OnChangedViewList(); // must be the last thing done to the document}void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint)// walk through all views{ASSERT(pSender == NULL || !m_viewList.IsEmpty());// must have views if sent by one of themPOSITION pos = GetFirstViewPosition(); //遍历所有观察者while (pos != NULL){CView* pView = GetNextView(pos);ASSERT_VALID(pView);if (pView != pSender)pView->OnUpdate(pSender, lHint, pHint);}}从代码中我们可以看到,AddView 和 RemoveView 相当于注册和注销操作,UpdateAllViews 相当于通知操作,通知操作会依次调用各个CView 对象的 OnUpdate,进行更新。
- 设计模式C++描述----04.观察者(Observer)模式
- 设计模式C++描述----04.观察者(Observer)模式
- 设计模式----观察者模式Observer(C++)
- 观察者设计模式Observer
- 观察者设计模式(observer)
- observer(观察者设计模式)
- Observer(观察者)设计模式
- [设计模式]观察者模式, Observer
- 设计模式--观察者模式(Observer)
- 设计模式-观察者模式(observer)
- [设计模式]Observer观察者模式
- [设计模式]观察者模式(Observer)
- 设计模式-Observer(观察者模式)
- 设计模式--observer观察者模式
- 设计模式 -- Observer 观察者模式
- 设计模式--观察者模式Observer
- 设计模式:观察者(observer)模式
- 设计模式-观察者模式Observer
- PostgreSQL获取table名,字段名
- 近期备忘
- 连接邮件
- 接口和抽象类的区别
- 学习过程
- 设计模式C++描述----04.观察者(Observer)模式
- 缓存依赖、数据库缓存依赖学习以及在LinQ当中使用缓存依赖
- js取select的text值和value值
- C++编程对缓冲区的理解
- 不输入文件名并创建名为.htaccess文件的方法
- php权威编程学习笔记
- 本地图片预览功能
- 软件实现过程中可交付的产品、评审、审计和基线
- 练习 jquery+Ajax+Json 绑定数据