佳礼资讯网

 找回密码
 注册

ADVERTISEMENT

查看: 2568|回复: 10

[原创]我谈设计模式(Design Pattern) 更新(06/08/2006)-观察者模式(Observer Pattern)

[复制链接]
发表于 27-7-2006 09:38 AM | 显示全部楼层 |阅读模式
[介绍篇]

如果你是负责编程设计的话, 你肯定会认同其实编程设计比编程更难做, 首要条件之一, 如果你是用OO语言你必需要很了解OO及要有远见, 当然还有很多其它, 这我也不多说, 我要说的是, 不管你愿不愿意, 你必须去尽你的可能把设计模式(Design Pattern)学好, 不然你设计的系统必定会遇很多"可以避免"的问题,例如:升级性, 可靠性, 维持性等等!这些问题多不多, 往往是看你编程设计的如何. 有一点值得一提, 通常我们花在开发的时间比捉虫(Debug)往往来的少, 意思是说我们无可避免无时无刻都会回顾(Review)我们所写的code,如果你所写的出现了以上所列出的编程设计问题, 你肯定会很头疼, 对于某些人, 可能抓回自己的虫或者改进可能不会觉得是一件难事, 但是如果你是捉你同事的虫或者改进, 你可能会呱呱叫,也许这还ok,因为team work嘛 最可怕的还是遇到有的占便宜就占的顾客, 多多要求, 重的话, 要你重新改很多,看你怕没!

人嘛, 本来就是很情绪化的动物, 如果能避免某些能令我们感情绪化的东西是最好不过,偏偏事不如人愿, 尤其编程人员无时无刻都会不知觉地卷入情绪中, 对某些人而言,抓虫或者提升现有的系统是一件可怕的事情, 他们会很害怕面对自己/或者同事所写的乱七八糟完全没有所谓编程设计的代码, 有者甚至不之如何下手, 如同海里捞针!不知者或许会问我编程设计的不好真的会带来这样的反效果吗?来来来, 我来证明给你看, 同时告诉你没有elegant code(中文叫:文雅代码吗?不管了, 就用文雅代码吧) 也有很大的反效果.


如果有一天, 你急着要找一本书,到了国家图书馆却发现所有的书都是乱乱放而没有根据索引或者目录,你是不是会因此急而陷入情绪中? 同样的道理, 如果你要抓虫的代码是乱七八糟一点文雅都没有, 得空来个interface, 无聊来个abstract class, 物体(Object)乱乱连接, 也不知懂不懂interface & abstract class 它们之间有什么区别也不知懂不懂什么叫loosly coupled,,这可能还ok, 如果连thread都没有好好控制, race-condition 无所不在等等,试问你你会有好的心情去捉虫吗? 如果你又赶着交呢? 你是不是会很容易陷入情绪中.其实代码本身就是很乱的东西, 做为编程人员我们必须保持平静,避免陷入情绪中, 因为情绪做事是会把事情复杂化, 一点帮助都没有!不囉唆, 我们来个真枪实弹的例子, 就拿QuickServer 和 Apache Mina 来做比较吧!

这两个都是TCP框架(framework) 用来开发网络系统(Network System), 我因为工作需要有幸碰到这两个框架, 用它们来做比较对我而言最好不过了. 先说明, 我可能用词不当,也可能用词会过分了一点, 但为了提高例子的说服力我不得不得罪某些清高道士读者, 当然如果你要别对号入座, 随你吧, 我也没办法.来咯...

QuickServer根本就是恶作剧, 作者还口口声声说是TCP 框架, 真的不知他那里来的勇气, 一个万万全全没有夸展性的框架叫框架吗? 可能作者也知道这一点, 而用这

QuickServer is an open source Java library/framework for quick creation of robust multi-client TCP server applications.

来介绍他的宝贝. 那到底, 这"框架"出现什么问题呢? 答案就是, 这"框架"的代码设计出了大问题, 几乎没什么用到设计模式. 试问一下, 不能夸展的"框架",怎能叫人去customize 呢?来来来, 我们一起"解剖"某些QuickServer的代码,







看到了吗?他的DataMode if-then-else真的太多了? 试想想, 如果我加一个新的DataMode是不是导致很多地方需要改, 这那来编程设计, 那来夸展性? 根本就是乱七八糟, 如果你有兴趣去看他的QuickServer class, 包你吐血, 因为作者竟然把不同的DataMode, NIO or Threaded Server通通放在同一个class.我觉得好的代码,象这种景况他应该用通用interface把不同的DataMode encapsulated 起来而只有一个地方加或者撤除,这样一来, 我如果加新的DataMode就不需要改别其它例如core的地方.以上的问题, Apache Mina 就巧妙的用很多不同的pattern(e.g Abstract Factory, Strategy, Chain of Responsibility) 把他框架夸展性提到最高!这框架用IoFilterChain把IOFiter做到你几乎随你喜好改你要的protocol handler,没有限制, 不但如此你还可以用这IOFilter做别的用途, 例如: IPFilter, AuthenticationFIlter 等等, 请看以下图片.(注:某些Filter我delete了).




此外, Apache Mina 还巧妙地应用IoConnector把udp, tcp 和vmPipe encapsulated 起来而又做到共同应用Apache Mina 的core,那真的是写的很好, 一流的设计呀!当然, 这还有许许多多, 我也不便一一写出,恐怕不是三言两语就能解释清楚.如果你有兴趣不妨下载这两个代码自己比较吧!

话虽然如此, 但应用QuickServer的人也不少, 原因可能是它开源代码吧, 而且又是免费的. 单单这一点作者们无私奉献, 我就自感不如, 所以呢, 我还是向他们致敬!也希望我能摆脱做钱奴才加入无私奉献轨道!

回到主题, 没有设计模式和幽雅的代码, 你可能用一个星期把任务完成, 但却用三星期时间做虫或者加新功能, 而有设计模式和幽雅的代码可能会花俩个星期时间去完成任务,但可以少过一星期做虫或者加新功能, 如果再加新功能,前者肯定会花的时间比后者多, 你同意吗?我说了那么多,到底设计模式是什么东西呢?答案是, 设计模式是一系列已经被证实的方案用来解决某些特殊的问题,与其自己探索(re-invent the wheel),不如直接拿已经被证实解决方法来用, 你用的妙,你的代码自然而然会趋向文雅.有一点我需要说, 虽然设计模式和幽雅的代码能节省许多的时间, 但是设计模式就好核子一样, 应用的好能带给你无穷的好处,但是如果你滥用或者不能控制它, 它可会带给你前所未有的灾难!

以上是我个人之见, 当然我会把我"抄袭"的内容一一放在参考以示我对原著的尊重, 欢迎大家来研究及发表, 我文笔不是很好, 不敢以笔会友, 但愿以编程会友!


先说明一点, 我也和你们一样必须工作维持生活, 我可能会没写下去因为工作关系, 请大家多多包含!当然如果有热烈的回应, 或许我会因为这一点而牺牲睡眠写下去!


References:

1. QuickServer
        (http://www.quickserver.org)
2. Apache Mina
        (http://directory.apache.org/subprojects/mina/index.html)
3. Design Patterns: Elements of Reusable Object-Oriented Software
        (http://www.awprofessional.com/bo ... 201633612&rl=1)


接下来, 我要谈几个最常用的设计模式....

[ 本帖最后由 黑木头 于 6-8-2006 09:20 PM 编辑 ]
回复

使用道具 举报


ADVERTISEMENT

发表于 27-7-2006 01:54 PM | 显示全部楼层
我没去研究那么深C的library,不过我承认设计模式的重要性。

在电脑店做工时期,改到不注重设计模式的代原码真的很抓狂。
回复

使用道具 举报

发表于 28-7-2006 08:46 AM | 显示全部楼层
很有参考价值的一篇文摘. 这个话题真的是非常值得好好讨论~
推一推~
希望有更多人能参与这话题~ 也希望楼主继续分享心得和看法
回复

使用道具 举报

发表于 28-7-2006 08:53 AM | 显示全部楼层
嗯。。是很好的分享。。等有时间我再写^^
回复

使用道具 举报

发表于 28-7-2006 08:53 AM | 显示全部楼层
看到了吗?他的DataMode if-then-else真的太多了?

那么应该如何呢??
回复

使用道具 举报

发表于 28-7-2006 09:26 AM | 显示全部楼层
你还抓不到楼主的主题吗?

就是不要把不同的DataMode, NIO or Threaded Server通通放在同一个class.

更强调 Apache Mina 就巧妙的用很多不同的pattern(e.g Abstract Factory, Strategy, Chain of Responsibility) 把他框架夸展性提到最高!

当设计一个大众化的模式,尤其是 Library (代原码库),升级性, 可靠性, 维持性例如考虑范围。
回复

使用道具 举报

Follow Us
 楼主| 发表于 28-7-2006 02:32 PM | 显示全部楼层
首先, 谢谢白老大你帮忙解释给某些不明白的朋友,也谢谢fxam兄把这帖加进精华, 有你们俩位论主的帮忙, 这帖会更有意思!好了, 客气的话, 我也不多说.

回到主题,在我还没进入谈某些最常用的设计模式, 我须补充几点, 其实呢, 只要你用的语言是物件导向(Object Oriented)(e.g C++, C#, VFP, Java, VB.net), 你都能用设计模式来解决某些特定的问题, 而我本身是比较专Java, 所以我很多时候都会用Java来做例子,但我可以肯定, 我的例子你都能一一转去其它语言.因为很多设计模式创造者都是用c++, 而设计模式的流行非提GoF(Gang of Four)不可,是他们的著作Design Patterns: Elements of Reusable Object-Oriented Software 把设计模式带到顶峰(Ref 1). 我从这本书学到很多东西.你不妨买一本来看.

对于初学者而言, 如果你们还没把物件导向精通, 你们可能会很吃力看这文章, 也有可能你们不懂我讲写什么, 这里我有小小的建议, 如果可以的话, 先把物件导向精通,最简单的方法是,多看多写, 别只是了解而已, 你还须把你所学的用在实际的工程里, 不然你所学的都会英雄无用武之地, 简单地说你根本就无法想象(Visualize)何时加入物件导向的"power"进你的代码里. 学设计模式也是一样, 你必须多看多写多看多写,因为这是高级物件导向, 别想一步登天, 这是不可能的,可以的话我希望你能做到让你的潜意识(subconscious)来控制你所学的设计模式.

潜意识?你我开玩笑, 不, 我是认真的. 给你的例子,为何我会这么说. 你还记得你刚刚学开车吗? 你是不是每做一样东西都很小心翼翼, 例如你会先绑安全带, 你会看着牙盘来转"gear", 对吗? 我想问你现在你还会那样驾车吗?答案肯定不会, 你可以一边开着车,一边绑安全带, 也无须看牙盘来转"gear",不但如此,你还能一边玩sms一边驾车, 一边讲电话或者想别的东西也会自然而然到达公司, 别跟我所你上班还须要看路牌,除非是新公司!这就是潜意识在工作, 想想如果你也能把你学的让潜意识帮你"发飞", 不管你做什么系统, 你所写的代码自然而然会有设计模式, 你同意吗? 那要如何办到呢, 就用你嘉车例子吧, 多看多写.....n, 就会了!

说回我谈设计模式,我已经在写着, 可是呢, 这里毕竟有很多深藏不露的武林高手, 我必须谨慎地写,不然我得罪了这一班武林高手,我可不知往那里逃生,毕竟我还是在学习当中,所以呢有一点慢 当然我如有什么出错的地方, 也欢迎高手们多多指教,先敬礼了!

如果你是初学者的话, 也欢迎你多多发问, 不一定要楼主帮你解答, 这里的高手们也会很乐意帮忙的.

I'll be right back in action....
回复

使用道具 举报

发表于 28-7-2006 05:50 PM | 显示全部楼层
原帖由 黑木头 于 28-7-2006 02:32 PM 发表
首先, 谢谢白老大你帮忙解释给某些不明白的朋友,也谢谢fxam兄把这帖加进精华, 有你们俩位论主的帮忙, 这帖会更有意思!好了, 客气的话, 我也不多说.

回到主题,在我还没进入谈某些最常用的设计模式, 我须补充几点 ...


谢谢你的分享,而我也可以从中学习到他人的编程经验,这是非常难得的。周末到了。。回家可以慢慢消化你所写的

在这里我知道goatstudio也是OO的高手之一,但他忙着筹备婚礼,所以因该不得空写
回复

使用道具 举报


ADVERTISEMENT

 楼主| 发表于 6-8-2006 09:14 PM | 显示全部楼层
Design Pattern的历史和种类我就不多说了,谈这些会很闷也很怕催眠读者, 毕竟我不是写书而是谈, 所以呢咋们直接进入实战吧!当然如果你对历史和种类有兴趣的话,你也可以从我的引用获取相关的资料.

现今很多系统都是用事件驱使(event-driven based),因为有事件驱使的系统往往能增加使用者互动感及系统整体的专业感, 简单地说, 所谓事件驱使就是你的系统会根据事件或者使用者的行动而采取直接的回应(responsive),类似的系统数不胜数, 可以说是无所不在. 在我们还没进入今天主题之前, 不如我们先暖身看看以下几个例子吧.

例子一 Bitcomet

Bitcomet相信对许多有宽带的人来说应该再熟悉不过了,
请看以下图片.



以上打圈的都是根据事件(incoming message)而采取直接的回应, 它的回应就是更新正在上/下载文件的状况,速度, 时间等等. 像这种事件驱使是无使用者直接的干涉, 它是系统本身根据某个事件而引发的回应, 至于谁引发事件, 可能是socket或者它的缓和剂(buffer moderator).

例子二 Eclipse

有用过eclipse的朋友应该会对它爱不释手, 当然我不是要打eclipse广告啦, 我要谈的是它的一小部分的功能用来做事件驱使例子. 先看图





这例子是捕获于新增new java class,每当你输入name 时, 它会根据你输入的name而引发某个事件, 而它采取的回应是, 检查你输入的name是否有同样的name已经添加了, 是否这name是正确的吗?如果发现有问题, 它会直接显现错误以及disable Finish按钮而不是等使用着按finish按钮才来做validation. 像这种依赖使用者的事件驱使, 几乎无所不在, 当然这包括windows本身在内, 比如, 当你移动你的mouse的指针在某些地方(e.g menu, quick launch),它们的背阴的颜色会有直接的变化, 这些都是GUI事件驱使在背后工作.此外,有一点我必须一提, 网页正在往这方面发展(e.g AJAX, Flash), 这种新的体系机构/科技就是要给使用者直接的回应及增加互动感, 例子如google 的Gmail, Google Suggest, Google Map etc.(Ref 1).

要做类似这种系统, 我非谈观察者模式(Observer)不可.那到底观察者模式是什么东西呢? 它在我之前所谈的升级性, 可靠性, 维持性等等又扮演了什么脚色?

从这模式名字来解说, 观察者模式提供一种很灵活的方法让一个物体(object)观察另外一个物体. 它们的关系是one-to-many(Ref 2), 意思是被观察者只有一个, 观察者可以有很多. 每当被观察者的状态改变, 有关的观察者都会一一被通知然后采取相关的行动(也就是以上我说的直接回应), 而被观察者是不懂观察者会采取怎样的行动, 它只需要通知它们而已, 很明显的好处是这种模式能大大增加升级性及维持性. 例如你改/更新某个观察者的代码时而无须怕影响其他的观察者或者需要修改被观察者的代码.

Observer class diagram(Ref 3)


Sample Application (Ref 2)


如果你有用过Java的Swing来开发GUI, 你应该对 MouseListener, ActionListener, KeyListener, ActionListener etc不谋生, 但你知道吗? 这些强大的event-handling功能都是用观察者模式建的, 当然为了到达fully resuable, 这event-handling功能还是有加用其它的模式(e.g Command, Composition pattern etc).(Ref 3).

为了要提高这观察者模式的说服力, 老子我一不做二不休花了三个钟写了一个简单的Downloader把以上我所谈到的一一展示出来, 好让有兴趣研究的朋友有个参考! 先说明一点, 这Downloader只是拿来做参考而已,可能里面还有可爱的胖胖(虫), 如果我的胖胖令你感到恶心的话, 先在此道歉.

Downloader 主页, 基本的功能有 Pause, Resume, Cancel 和clear.在File Menu里有add download.


与Eclipse 的add new class相同, 这Downloader 的 add download 有直接的validation. 如果使用者输入的url 不正确或者已经在downloading list 里面, add 按钮是会disabled.

URL错误


重复URL错误


另外, 我还写了一个很简单的library 用来快速开发事件驱使系统, 有兴趣的朋友不妨拿来试用,以下是library 的代码.

IListener

  1. package blackwood.util;

  2. public interface IListener{
  3.        
  4. }
复制代码


ListenerEvent

  1. package blackwood.util;

  2. public abstract class ListenerEvent{
  3.     public ListenerEvent(){}
  4.        
  5.     @Override
  6.     public String toString() {
  7.             return this.getClass().getSimpleName();
  8.         }
  9. }
复制代码


ListenerHandler

  1. package blackwood.util;

  2. import java.util.HashSet;
  3. import java.util.Set;

  4. public abstract class ListenerHandler<T extends IListener> {   
  5.         private Set<T> listenerSet = new HashSet<T>();
  6.        
  7.         protected abstract void notifyListener(T listener, ListenerEvent event);
  8.        
  9.         public ListenerHandler(){}
  10.        
  11.         public void addListener(T listener) {
  12.                 synchronized (listenerSet) {
  13.                         listenerSet.add(listener);
  14.                 }
  15.         }
  16.        
  17.         public void removeListener(T listener) {
  18.                 synchronized (listenerSet) {
  19.                         listenerSet.remove(listener);
  20.                 }
  21.         }
  22.        
  23.         public void removeAllListeners(){
  24.                 synchronized (listenerSet) {
  25.                         listenerSet.clear();
  26.                 }
  27.         }   
  28.        
  29.         @SuppressWarnings("unchecked")
  30.         protected  void fireEvent(ListenerEvent event){
  31.                 IListener[] tempListeners;
  32.                
  33.                 synchronized (listenerSet) {
  34.                         tempListeners = new IListener[listenerSet.size()];
  35.                        
  36.                         listenerSet.toArray( tempListeners);
  37.                 }
  38.                
  39.                 //Notify registered listener one by one
  40.                 for (int i = 0; i < tempListeners.length; i++){                                       
  41.                         notifyListener((T) tempListeners[i],event);
  42.                 }
  43.         }
  44.        
  45.         public int getTotalListeners(){
  46.                 return listenerSet.size();
  47.         }
  48.        
  49.         public String toString() {
  50.                 return this.getClass().getSimpleName();
  51.         }
  52. }
复制代码


这library代码短的可怜,相信无须解释吧!至于如何用, 你可以参考Downloader的代码, 我不post上来,是因为太多的代码会把这帖变成很乱, 重点是, 这library用在data entry上会有很大的帮助, 比如你用一个叫studentController来负责addStudent, updateStudent 和deleteStudent, 而那些对于这些事件感兴趣的可以做为这studentController的观察者(e.g studentTree, studentTable 等等).

来一例子, 每当有新加student时studentController就引发addStudent事件, 而studentTree 就会加一新的TreeNode, 而studentTable 就会加新的row. 当然你可以有其它的观察者来观察studentController而无须担心怕影响现有的观察者也无需更改studentController的代码, 这对于代码来说已经很有升级性, 你同意吗?

这观察者模式最大缺点是, 你必须很小心define事件, 因为被观察者和观察者都是依赖事件来沟通, 如果事件define的不好, 两者都必需更改, 这就是我之前说的, 设计模式就好核子一样, 应用的好能带给你无穷的好处,但是如果你滥用或者不能控制它, 它可会带给你前所未有的灾难!

Refrence:
==========
Ref 1: AJAX in Action
        URL: http://www.javarss.com/ajax/j2ee-ajax.html

Ref 2: Design Pattern, Elements of reusable Object-Oriented Software
        URL: http://www.awprofessional.com/title/0201633612

Ref 3: Applied Java Patterns
        URL: http://authors.phptr.com/appliedjavapatterns/

Resource:
=========
Downloader
        URL                : http://rapidshare.de/files/28385605/DownloadTool.rar.html
        Requirement         : jdk1.5, Eclipse
        Start Class         : blackwood.downloader.RunDownloader               

Tested URL for Downloader
========================
http://download.bitcomet.com/tracker/achive/BitCometTracker_0.3.zip
http://down5.flashget.com/fgf172.exe
http://download.nullsoft.com/winamp/client/winamp524_lite.exe

[ 本帖最后由 黑木头 于 6-8-2006 09:21 PM 编辑 ]

评分

参与人数 1积分 +50 收起 理由
fxam + 50

查看全部评分

回复

使用道具 举报

发表于 21-8-2006 07:58 PM | 显示全部楼层
最近發現一本關於event的好书:
Event-Based Programming: Taking Events to the Limit
回复

使用道具 举报

发表于 24-4-2011 11:42 PM | 显示全部楼层
http://rapidshare.de/files/28385605/DownloadTool.rar.html
FILE NOT EXISTE!可以在SHARE 吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

 

ADVERTISEMENT



ADVERTISEMENT



ADVERTISEMENT

ADVERTISEMENT


版权所有 © 1996-2023 Cari Internet Sdn Bhd (483575-W)|IPSERVERONE 提供云主机|广告刊登|关于我们|私隐权|免控|投诉|联络|脸书|佳礼资讯网

GMT+8, 13-5-2024 10:12 AM , Processed in 0.060753 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表