设计模式4-Observer(观察者模式)

来源:互联网 发布:阿里云域名管理地址 编辑:程序博客网 时间:2024/06/13 19:00
 

 /**********************************************************************************************************************/
* Observer模式观察者模式
* [说明]
*  在一公文处理系统中,开发者定义了一个公文类OfficeDoc, 其中定义了公文具有的属性和处理公文的相应方法。当公文件的内容或
* 状态发生变化时,关注此OfficeDoc 类对象的相应的DocExplorer 对象都要更新其自身的状态。一个OfficeDoc 对象能够关联一组
* DocExplorer 对象。当OfficeDoc 对象的内容或状态发生变化时,所有与之相关联的DocExplorer对象都将得到通知,这种应用被称
* 为观察者模式。
*
* 例如MFC的DOC、VIEW架构都是基于这种观察者的模式。
* 我们可以将Factory理解成生产制造模式,即给定一个特定值(字符串/ 枚举), 产生不同子类的对象

* 意图: 通过一个统一的接口, 通知所有需要更新的类的对象
* 适用性:  当某个对象变化时, 通知(命令)一组对象更新;

/**********************************************************************************************************************/


#include <stdio.h>
#include <typeinfo>

// 最多与OfficeDoc关联的DocExplorer对象的个数
const int OBS_MAX = 20;

class COfficeDoc;

// 关注OfficeDoc公文对象的类
//##ModelId=44D02B1A01B9
class CDocExplorer
{
  static int ObjectIndex;//全局的
public:
  COfficeDoc *m_doc;
 //##ModelId=44D02B1A01BA
 CDocExplorer(COfficeDoc *doc);

  ~CDocExplorer();
 //##ModelId=44D02B1A01BC
 void UpdateSelf(COfficeDoc *doc);

 // 为了实现对象的识别,在此加一个标示
 //##ModelId=44D02B1A01BE
  int nExplorerID;
};

//##ModelId=44D02B1A01D4
class COfficeDoc
{
public:
 //##ModelId=44D02B1A01D5
 COfficeDoc()
 {
  index = 0;
    printf("COfficeDoc对象创建...\n");
 }
  ~COfficeDoc()
  {
     printf("COfficeDoc对象释放...\n");
  }
 
 //##ModelId=44D02B1A01D6
 void Attach(CDocExplorer *e)
 {
  if(index >= OBS_MAX || e == NULL)
  {
   return;
  }
  myObs[index] = e;
  index++;

  //e->nExplorerID = index;
 }

 //##ModelId=44D02B1A01E4
 void Detach(CDocExplorer *e)
 {
  for(int i = 0; i <index; i++)
  {
   if(myObs[i] == e)
   {
    // 把当前位置的观察者对象和最后一个对象交换,并把index的值减一个
    if(i <= index-2)
     myObs[i] = myObs[index-1];
    myObs[index - 1] = NULL;
    index--;
    break;
   }
  }
 }
 
 // 修改数据,并通知观察者更新
 //##ModelId=44D02B1A01E6
 void ModifyData(int data)
 {
  printf("公文的数据改变成:%d\n", data);
  m_nData = data;
  NotifyObs();
 }

private:
 //##ModelId=44D02B1A01E9
 CDocExplorer *myObs[OBS_MAX];  // 观察者的类对象指针数组
 //##ModelId=44D02B1A01F4
 int index;//个数

 // 通知所有的观察者对象改变自己的状态
 //##ModelId=44D02B1A01F5
 void NotifyObs()
 {
  for(int i = 0; i < index; i++)
  {
   myObs[i]->UpdateSelf(this);
  }
 }
 
public:
 // 公文的数据
 //##ModelId=44D02B1A01F6
 int m_nData;
};

int  CDocExplorer::ObjectIndex=0;

//##ModelId=44D02B1A01BA
CDocExplorer::CDocExplorer(COfficeDoc *doc)
{
  m_doc=NULL; 
  if (!doc)
  {
    return;
  }
  m_doc=doc;
  ObjectIndex++;
  nExplorerID=ObjectIndex;
  printf("观察者%d创建...\n", nExplorerID);
 m_doc->Attach(this); 
}
CDocExplorer::~CDocExplorer()
{
  if (m_doc)
  {
    m_doc->Detach(this);
  }
  printf("观察者%d释放...\n", nExplorerID);
  
}

//##ModelId=44D02B1A01BC
void CDocExplorer::UpdateSelf(COfficeDoc *doc)
{
 // 把下面两行的注释打开还可以看到typeid和type_info的用法
 // 会发现typeid只能实现类型的识别

 //const type_info &t = typeid(*doc);
 //printf("我正在观察%s\n", t.name());
 
 printf("我是观察者%d, ", nExplorerID);
 printf("更新数据: %d \n", doc->m_nData);   
}

 

int main()
{
 COfficeDoc officeDoc;
 CDocExplorer docExplorer0(&officeDoc);
 CDocExplorer docExplorer1(&officeDoc);
 CDocExplorer docExplorer2(&officeDoc);
 CDocExplorer docExplorer3(&officeDoc);
 CDocExplorer docExplorer4(&officeDoc);
 
 // 更新公文的数据
 officeDoc.ModifyData(123);
 printf("\n");
 officeDoc.ModifyData(567);
 
 return 0;
}