快速业务通道

设计模式之观察者(Observer)模式与其C++通用实现(下)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29

我们在《设计模式之观察者(Observer)模式与其C++通用实现(中)》一文中给出了一个以C++语言实现的通用观察者模式方案骨架。然而,实际的工程项目需求往往要比理想状态复杂得多,此篇便是与读者一起探讨在现实世界中可能遇到的各种棘手问题及解决方案。

我把目前为止我所遇到的问题罗列如下:

复合主题

多线程

更新方法修改观察者链表

接下来我们一一给予讨论。

(一)复合主题

考虑GUI的组件设计,我习惯用Widget类代表之,它需要处理许多用户交互以及系统事件,其中最常见的用户交互事件有鼠标及键盘事件。倘若架构师决定以事件监听方式设计整个UI框架,那么Widget便具有主题的角色,相应的,鼠标及键盘事件便是观察者角色。实际上,一个主题对应多种(不是多个)观察者的现象很普遍。

我们借助中篇所给的观察者模式骨架实现这类应用。

借助多继承机制,很容易办到:

01.struct MouseListener {
02. void mouseMoved(int x, int y) {}
03.};
04.
05.struct KeyListener {
06. void keyPressed(int keyCode) {}
07.};
08.
09.class Widget : public BasicSubject<MouseListener>, public BasicSubject<KeyListener>{...};

添加事件监听器的伪代码大致如下:

01.MouseListener mel;
02.KeyListener kel;
03.Widget w;
04.w.addObserver(mel);
05.w.addObserver(kel);

为了使Widget添加/移除事件监听器的方法更加友好,我们可以为Widget提供addXXXListener/removeXXXListener 方法,这些方法会把调用转给基类。有了这些相对较友好的接口后,基类的addObserver/removeObserver接口对用户已经没有用了,所以我们可改用protected继承。综合起来,代码看起来大致像这样:

01.class Widget : protected BasicSubject<MouseListener>,protected BasicSubject<KeyListener>{
02. typedef BasicSubject<MouseListener> MouseSubject;
03. typedef BasicSubject<KeyListener> KeySubject;
04.public:
05. inline void addMouseListener(MouseListener &mel) {
06. MouseSubject::addObserver(mel);
07. }
08.
09. inline void removeMouseListener(MouseListener &mel) {
10. MouseSubject::removeObserver(mel);
11. }
12.
13. inline void addKeyListener(KeyListener &kel) {
14. KeySubject::addObserver(kel);
15. }
16.
17. inline void removeKeyListener(KeyListener &kel) {
18. KeySubject::removeObserver(kel);
19. }
20.
21. void handleMsg(int msg) {
22. if (msg == 0) {
23. MouseSubject::notifyAll(&MouseListener::mouseMoved, 1, 1);
24. } else if (msg == 1) {
25. KeySubject::notifyAll(&KeyListener::keyPressed, 100);
26. }
27. }
28.};

当然,你也可以不使用继承改而使用组合技术实现,这完全取决于你的爱好。组合版本的实现大致是像这样的:

01.class Widget {
02.public:
03. inline void addMouseListener(MouseListener &mel) {
04. ms_.addObserver(mel);
05. }
06.
07. inline void removeMouseListener(MouseListener &mel) {
08. ms_.removeObserver(mel);
09. }
10. ...
11.private:
12. BasicSubject<MouseListener> ms_;
13. BasicSubject<KeyListener> ks_;
14.};

(二)多线程

倘若我们的应用程序运行在多线程环境中,那你可要谨慎了。试想线程A正在添加观察者的同时另一线程B也试图添加观察者吧。我们默认使用的容器std::list是线程非安全的,所以我们的BasicSubjcet也会是线程非安全的。要解决此

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号