1. 基于继承的实现方式.
废话:这是Observer模式的基本实现方式,在GOF的设计模式或其它介绍设计模式书中提到的就是这种方式。JDK1.1以后的版本中的AWT就是以这种方式实现的.
(1)结构: 以下这个图把Observer模式的基于继承实现方式表现得很明白了.
(2)类说明:
Subject:目标基类. 维护了所支持的观察者类列表.实现增加/删除观察者接口
ConcreteSubject:目标具体类. 通过观察者基类提供的消息响应接口,将新消息广播给已注册观察者.
Observer:观察者基类. 定义消息响应接口函数(Update())供目标类调用.可维护目标引用用于在响应消息时访问目标数据(对目标数据的获取有推和拉模型,也可以通过把感兴趣的消息类型告诉目标从而避免目标对所有消息都进行广播,从而提高性能)
ConcreteObserver:观察者具体类。实现消息响应函数.
(3)应用。
前些日子在公司写的一个某硬件终端模拟软件时,应用了基于事件的继承方式。即观察者类Update函数的参数为Event事件基类指针,在Event的派生类中可包含目标引用,事件类型及其相关数据。对事件的封装方便多种事件的监听,同时能解决不同事件所关联数据类型不同的问题。
2. 基于事件/委托的实现方式
废话:这种实现方式不好理解,不过在某些方面比继承方式更灵活,比如观察者处理消息的方法不必是观察者接口预先定义好的方法,可以是任何符合特定要求的方法。在《道法自然》书中有提到这种实现方式。 .NET的消息模型就是这种实现方式。但我感觉这种方式把问题复杂化了,上面提到的基于事件的继承方式也能达到委托方式的效果,而且还解决了在同一响应函数中响应多种事件的问题。
(1)结构。懒得画了,待会直接上代码和注释。
(2)类说明:
IObject:目标和观察者的共同基类;
IDelegate:委托接口。维护了一个委托映射(事件对象->委托函数(事件响应方法引用或指针));
CMultiDelegate:多播委托类。结合composite模式实现的树状委托链;
IEvent:事件接口。为目标维护一个多播委托对象;
CEventTemplate:事件模板工厂类。为事件接口创建目标所支持的委托对象。
CController:目标具体类。1定义支持的委托类(委托函数),2维护事件对象
CDisplayResult:观察者具体类。实现监听目标类所支持的委托函数。
COperatorA, COperatorB:即是目标也是观察者。
(3)代码。 参考 道法自然 书里的代码并加上个人理解的注释。
#include <iostream>
using namespace std;
//目标和观察者共同接口
class IObject
{public:
};
class IEvent;
//委托接口。//对客户可见
class IDelegate
{
public:
typedef void (IObject::*ONEvent)(void); //响应方法(委托函数,可被具体子类重定义成其它带参数形式(参数由m_event提供))
void SetEventMap(IEvent* event, IObject* obj, ONEvent onEvent) //设置事件映射
{ m_event = event;
m_obj = obj;
m_onEvent = onEvent;
}
//
virtual void Invoke() = 0; //调用委托函数的函数,由子类实现(因委托函数可被重写,即委托函数调用方式不固定,由子类特殊处理)
protected:
IEvent* m_event; //事件
IObject* m_obj; //委托函数所属类
ONEvent m_onEvent; //委托函数
};
//多播委托类。维护两个子委托对象 //对IEvent可见
class CMultiDelegate: public IDelegate //只继承方法,放弃基类成员变量?
{
public:
CMultiDelegate(IDelegate* pA, IDelegate* pB):m_pDelegateA(pA), m_pDelegateB(pB) { }
virtual void Invoke()
{ if (m_pDelegateA)
m_pDelegateA->Invoke();
if (m_pDelegateB)
m_pDelegateB->Invoke();
}
protected:
IDelegate* m_pDelegateA;
IDelegate* m_pDelegateB;
};
//事件接口。维护当前事件的一个多播委托对象(即关联了所有相关委托)
//对IDelegate可见
class IEvent
{
public:
IEvent()
{ m_pDelegate = NULL;
}
//
void AddDelegate(IObject* pObj, IDelegate::ONEvent onEvent)//增加新委托(即对此事件的新监听者)
{
m_pDelegate = new CMultiDelegate(m_pDelegate, CreateDelegate(pObj, onEvent)
} //
void Invoke() //开始多播
{
if (NULL != m_pDelegate)
m_pDelegate->Invoke();
}
virtual IDelegate* CreateDelegate(IObject* pObj, IDelegate::ONEvent onEvent) = 0;//工厂方法,
private:
IDelegate* m_pDelegate;
};
//事件的模板工厂类. //对客户可见
template<class DELEGATE>
class CEventTemplate:public IEvent
{
public:
virtual IDelegate* CreateDelegate(IObject* pObj, IDelegate::ONEvent onEvent)
{
IDelegate* pDelegate = new DELEGATE;
pDelegate->SetEventMap((IEvent*)this, pObj, onEvent);
return pDelegate;
}
};
//目标具体类,控制者 (支持的委托函数原型为typedef void (IObject::*ONEvent)(int i);)
class CController:public IObject
{
public:
void UpdateEvent(int i) //事件/状态更新时进行事件多播
{
printf("[控制者]目标C有新事件,开始多播并向观察者委托函数传递参数int i=%d\n",i);
m_event.SendEvent(i);
}
//
void Regist(IObject* pObserver, IDelegate::ONEvent onEvent) //注册委托
{
m_event.AddDelegate(pObserver, onEvent);
}
private:
//
class MyDelegate:public IDelegate
{
typedef void (IObject::*ONEvent)(int i); //重定义委托函数为带int参数的版本
virtual void Invoke()
{
//把基类的委托函数指针转化成本委托支持的委托函数原型来调用
(m_obj->*(ONEvent)m_onEvent)(((MyEvent*)m_event)->nParam);
}
};
//
class MyEvent:public CEventTemplate<MyDelegate>
{
public:
void SendEvent(int i) //因所支特委托函数版本不为委托类默认版本,需先作一些特殊设置
{
nParam = i;
Invoke();
}
public:
int nParam; //提供给本目标所支特的委托函数版本的参数
};
MyEvent m_event; //委托事件
};
//控制者的观察者 / 也是目标具体类,操作者A (支持的委托函数原型为typedef void (IObject::*ONEvent)(float f);)
class COperatorA:public IObject
{
public:
COperatorA(CController* pConn)
{
pConn->Regist(this, (IDelegate::ONEvent)&COperatorA::OnUpdateByConn );
}
//
void OnUpdateByConn(int i) //实现控制者支持的委托函数
{
printf("[操作者A]从控制者接收到事件更新,参数int i=%d,开始执行操作:i*i*0.1\n",i);
//多播给自已的观察者
m_event.SendEvent(i*i*0.1);
}
//
void Regist(IObject* pObj, IDelegate::ONEvent onEvent)
{
m_event.AddDelegate(pObj, onEvent);
}
private:
class MyDelegate:public IDelegate
{
typedef void (IObject::*ONEvent)(float f); //重定义委托函数为带int参数的版本
virtual void Invoke()
{
//把基类的委托函数指针转化成本委托支持的委托函数原型来调用
(m_obj->*(ONEvent)m_onEvent)(((MyEvent*)m_event)->fParam);
}
};
//
class MyEvent:public CEventTemplate<MyDelegate>
{
public:
void SendEvent(float f) //因所支特委托函数版本不为委托类默认版本,需先作一些特殊设置
{
fParam = f;
Invoke();
}
public:
float fParam; //提供给本目标所支特的委托函数版本的参数
};
MyEvent m_event; //委托事件
};
//控制者的观察者 / 也是目标类,操作者B (支持的委托函数原型为typedef void (IObject::*ONEvent)(bool b);)
class COperatorB:public IObject
{
public:
COperatorB(CController* pConn)
{
pConn->Regist(this, (IDelegate::ONEvent)&COperatorB::OnUpdateByConn );
}
//
void OnUpdateByConn(int i) //实现控制者支持的委托函数
{
printf("[操作者B]从控制者接收到事件更新,参数int i=%d,开始执行操作:i>10?\n",i);
//多播给自已的观察者
m_event.SendEvent(i>10);
}
//
void Regist(IObject* pObj, IDelegate::ONEvent onEvent)
{
m_event.AddDelegate(pObj, onEvent);
}
private:
class MyDelegate:public IDelegate
{
typedef void (IObject::*ONEvent)(bool b); //重定义委托函数为带int参数的版本
virtual void Invoke()
{
//把基类的委托函数指针转化成本委托支持的委托函数原型来调用
(m_obj->*(ONEvent)m_onEvent)(((MyEvent*)m_event)->bParam);
}
};
//
class MyEvent:public CEventTemplate<MyDelegate>
{
public:
void SendEvent(bool b) //因所支特委托函数版本不为委托类默认版本,需先作一些特殊设置
{
bParam = b;
Invoke();
}
public:
bool bParam; //提供给本目标所支特的委托函数版本的参数
};
MyEvent m_event; //委托事件
};
//同时是操作者A和操作者B的观察者
class CDisplayResult:public IObject
{
public:
CDisplayResult(COperatorA* pOptA, COperatorB* pOptB)
{
if (NULL != pOptA)
pOptA->Regist(this, (IDelegate::ONEvent)&CDisplayResult::OnUpdateByOptA);
if (NULL != pOptB)
pOptB->Regist(this, (IDelegate::ONEvent)&CDisplayResult::OnUpdateByOptB);
}
//
void OnUpdateByOptA(float f)
{
printf("[显示结果]从操作者A接收到事件更新,参数float f=%f\n",f);
}
//
void OnUpdateByOptB(bool b)
{
printf("[显示结果]从操作者B接收到事件更新,参数结果为bool b=%b\n",b);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
//2基于委托的观察者模式
cout<<"#####一个操作者#####"<<endl;
CController conn;
COperatorA optA(&conn);
CDisplayResult display(&optA, NULL);
conn.UpdateEvent(5);
conn.UpdateEvent(10);
cout<<endl<<"#####两个操作者#####"<<endl;
CController conn2;
COperatorA optA2(&conn2);
COperatorB optB2(&conn2);
CDisplayResult display2(&optA2, &optB2);
conn2.UpdateEvent(5);
conn2.UpdateEvent(10);
//1
// testVld();
int n;
return 0;
}
(4)代码运行结果。