在编写UI程序中通常会遇到以下问题:
1、 在交互过程中会有很多事件,这些事件的处理者与产生者之间的联系并不紧密。如:下载的文件完成、下载进度更新、游戏程序扫描完成等。
2、 有可能一个事件对应多个处理。
3、 这些事件通常与界面更新相关。为了避免多线程UI问题通常要在特定的线程(主线程)中调用事件相关的处理函数。
4、 事件描述对象可能要在多个线程中使用,并有可能被处理对象持有很长时间,因此内存的释放比较麻烦。
可以使用以下方式来解决上述问题:
1、 使用发布/订阅模式来解藕事件的产生者和事件的响应者之间的关联。
2、 使用单例模式建立全局的发布/订阅模式对象来统一处理这类事件,它的任务是提供单一的注册点并实现必要的线程切换。
3、 发布者和订阅者都以字符串形式的“topic”相互绑定,在订阅topic时可以使用类似“*”这种通配符。
4、 发布者和订阅者都知道事件描述对象的定义。
5、 通过事件描述对象继承自支持引用记数的CSharedPtrBase类来实现内存的释放。
思考:如何提高topic匹配的处理效率
以下是框架示例代码:
class CSharedPtrBase
{
public:
virtual~CSharedPtrBase() {}
virtuallong AddRef()
{
returnm_RefCount.Inc();
}
virtualvoid Release()
{
if(m_RefCount.Dec() == 1)
deletethis;
}
longGetRefCount()
{
returnm_RefCount.Get();
}
protected:
CDefAtomicm_RefCount;
};
typedef std::tr1::function<void(constWString&, CSharedPtrBase*)> CTopicProcessor;
class CPublisher
{
public:
staticCPublisher* instance(); // for singlton
voidNotify(const WString& strTopic, CSharedPtrBase* pDetail);
intSubscribe(const WString& strTopic, const CTopicProcessor& Processor);
voidUnsubscribe(int iKey);
};
class CSubscriber
{
public:
voidDownloadDone(const WString& strTopic, CSharedPtrBase* pDetail)
{
cout<< strTopic << endl;
}
};
int main(int argc, char *argv[])
{
CSubscriberSubscriber;
CPublisher::instance()->Subscribe(L"download_done*",std::tr1::bind(CSubscriber::DownloadDone, &Subscriber, _1, _2));
CPublisher::instance()->Notify(L"download_donec:\\test.txt", NULL);
return0;
}