当报表系统业务数据变化时,它要通知依赖它的所有视图发生相应的变化,这样就需要在业务数据对象里记录依赖它的视图,或是增加一个关联查找机制。这两种方法在数据和视图间依赖关系比较少时可以高效的解决问题,但当它们之间的关系特别复杂时,我们就需要一个专门的对象来维护这些关系,这里我们称之为更改管理器(ChangeManager),它的目的是尽量减少视图反映数据变化所需的工作量。例如,如果一个操作涉及到对几个相互依赖的目标进行改动,就必须保证仅在所有的目标都已经更改完毕后,才一次性的通知它们的观察者,而不是每个目标都通知观察者。另外,观察者并不是对所有的事件都感兴趣,可以扩展目标的注册接口,让个观察者注册为仅对特定事件感兴趣,以提高更新的 效率。当一个事件发生时,目标仅通知那些已注册为对该事件感兴趣的观察者。
Observer模式在报表系统中的层次结构如图1所示,其中DataEntry为业务数据抽象,它的具体实现由ConcreteDataEntry来完成;UserView是显示视图的抽象,具体使用的视图由ConcreteUserView实现;更改管理器(ChangeManage)的实现有两种:SimpleChangeManage和DAGChangeManage ,它们分别管理单一目标的目标—观察者关系和多目标相互关联的目标—观察者关系。
其中业务数据的类定义如下:
class DataEntry{
public :
virtual ~DataEntry();
virtual void Attach(UserView *pView ); //增加视图
virtual void Detach(UserView *pView); //删除视图
virtual void Notify(UserView *pSender); //通知
protected:
DataEntry ();
private:
List *UserViewList; //记录视图
}
显示视图的定义为:
class UserView{
public:
DataEntry getD
ataEntry(); /*获取业务数据实体的状态,相当于模式中的GetState()和SetState()*/
virtual void Notify (UserView *pView);
virtual void OnDraw(UserView *pView);
//设计为虚函数以供重载
protected:
List *DataEntryList;
//记录业务数据实体
}
在这里简要说明一下Notify()的实现:
void Notify:: DataEntry (UserView *pSender){
ASSERT(pSender==NULL||*UserViewList.IsEmpty()); //判断视图列表是否为空
POSITION pos = GetFirstViewPosition ();
While (pos! = NULL)
{UserView* pView = GetNextView (pos);
ASSERT_VAILD (pView);
if (pView != pUserView)
pView->Notity ();}
3.2 适配器模式(Adapter)
在许多大型企业及某些行业的局域网或广域网内,由于历史和技术发展的原因存在着多种数据库同时在运行的情况,比如某大型企业、某地区的电力单位或电信公司等,可能正同时在使用着多种数据库(Oracle, DB2, SQL Server, Sybase 或Informix等)。在这样多的数据库并存的环境下,要求能任意访问到这些数据库,实现多种数据库间的数据转化、资源共享、数据一致性和完整性成为系统开发和应用中一个尤为突出的问题。