事件编程(二)
2007-03-15 21:54:00 来源:WEB开发网核心提示: inline IPrimeEvents::~IPrimeEvents() { }有了我的仿函数定义,CPrimeCalculator 是这样触发 Progress 事件的:// in CPrimeCalculator:void NotifyProgress(UINT nFound){for
inline IPrimeEvents::~IPrimeEvents() { }
有了我的仿函数定义,CPrimeCalculator 是这样触发 Progress 事件的:// in CPrimeCalculator:
void NotifyProgress(UINT nFound)
{
for_each(m_clients.begin(), m_clients.end(),
IPrimeEvents::Progress(nFound));
}
到这里,我已经介绍了仿函数类 Progress 和 Done,同时,NotifyProgress 和 NotifyDone 都能用 STL 的 for_each 算法。下一步该做什么?记住,我的目的是完全摆脱 NotifyFoo 函数——或者说得更具体一点,就是把它们实现为模板,以便程序员在创建事件时不必为他们定义的每个事件编写千篇一律的函数。将 for 循环转化为 for_each 算法只是万里长征的第一步。通过将虚拟成员函数 OnFoo 转换为 Foo 仿函数类型,从而为模板化创造条件。(仿函数在这里有点像 .NET 中的委托。)现在我的通知函数根据类型的不同而不同,替代了函数名,我可以将它们参数化。这样一来,我便可以将整个事件实现移出 CPrimeCalculator ,把它们放入新的模板类 CEventMgr 中,这是一个完全通用的类。如 Figure 3 所示。CEventMgr<I> 保存 I* 指针列表。它具备 Register 和 Unregister 方法以便添加元素和从其列表中删除元素,此外它还有一个模板成员函数 Raise 用于触发事件:
template
class CEventMgr
{
...
template
void Raise(F fn)
{
for_each(m_clients.begin(), m_clients.end(), fn);
}
};
很难相信,平时几乎碰不到的模板套模板的情况?在此处派上用场了。现在触发事件我们可以这样做:void NotifyProgress(UINT nFound)
{
m_eventmgr.Raise(IPrimeEvents::Progress(nFound));
}
没有 for 循环,甚至都没有 for_each,所有细节都被封装在 CEventMgr 之中,事件的触发使用一行代码。我甚至可以完全省略掉 NotifyProgress,每当想要触发事件时仅仅调用 CEventMgr::Raise 即可——然而,好的编码规范促使我宁愿将 Raise 封装在某个函数中,以防万一我要修改 CEventMgr 或将事件触发函数暴露给客户机。既然 NotifyProgress 是内联函数,就不会有幸能丢失。
更多精彩
赞助商链接