本书是一本试图用实战案例阐释面向对象技术体系的指南。本书共分19章,通过实际的开发案例——FishGUI项目为主线依次介绍了需求和用例分析、面向对象分析、架构分析、面向对象设计、设计模式、编码技巧等几个主要的技术领域,并基本按照时间顺序,描述了FishGUI系统设计和实现的全过程。
如果把面向对象大师们偏重理论建构的经典读物称为面向对象盛宴中的主菜,那么,这本指南若能充当佐餐的凉菜或是饭后的甜点,作者就心满意足了。本书适合所有在软件开发领域辛勤工作的开发人员、管理人员、系统分析人员、测试人员、技术支持人员等阅读。
第1章 需求分析:追求完美vs.容忍缺陷
在生活的任何领域寻求完美,都不过是抽象的、病态的或无聊的幻想而已。
——车尔尼雪夫斯基,《艺术与现实的审美关系》
第2章 用例分析:海底总动员vs.云中漫
横看成岭侧成峰,远近高低各不同。不识庐山真面目,只缘身在此山中。
——苏轼,《题西林壁》
第3章 设计方法:面向过程vs.面向对象
思想的真正客观性应该是:思想不仅是我们的思想,同时又是事物的自身,或对象性的东西的本质。
——黑格尔,《小逻辑》
第4章 模式:变化之美vs.永恒之道
老僧三十年前未参禅时,见山是山,见水是水。及至后来,亲见知识,有个入处,见山不是山,见水不是水。而今得个休歇处,依前见山只是山,见水只是水。
——释普济,《五灯会元》,第十七卷
第5章 分析模型:实体类vs.软件类
不,我不想要自由;我只要条出路,向左或是向右,到哪儿都行。
——卡夫卡,《致科学院的报告》
第6章 架构分析:功能分解VS.对象分析
天下莫大于秋豪之末,而大山为小;莫寿于殇子,而彭祖为夭。天地与我并生,而万物与我为一。既已为一矣,且得有言乎?既已谓之一矣,且得无言乎?
——《庄子·齐物论》
第7章 面向对象设计:共性VS.个性
一尺之捶,日取其半,万世不竭。
——《庄子·天下》
第8章 外观模式:统一接口VS.暴露细节
百事有所出,而独知守其门。
——《淮南子·原道》
第9章 观察者模式:间接依赖VS.直接依赖
你以为那很奇怪吗?什么事情都逃不过旁观者的冷眼;渊深莫测的海底也可以量度得到,潜藏在心头的思想也会被人猜中。
——莎士比亚,《特洛伊罗斯与克瑞丽达》,第三幕
第10章 单件模式:隐式全局变量VS.显式全局变量
云长笑曰:“……吾来日独驾小舟,只用亲随十余人,单刀赴会,看鲁肃如何近我!”
——罗贯中,《三国演义》,第六十六回
第11章 复合模式:透明VS.安全
谁是那个总是走在你身旁的第三人?
我数的时候,只有你和我在一起
但是我朝前望那白颜色的路的时候
总有另外一个在你身旁走
——艾略特,《荒原》
第12章 迭代器模式:继承VS.模板
道生一,一生二,二生三,三生万物。
——《老子》,第四十二章
第13章 创建型模式:工厂方法VS.抽象工厂
神说:“水要多多滋生有生命的物,要有雀鸟飞在地面以上,天空之中。”神就造出大鱼和水中所滋生各样有生命的动物,各从其类;又造出各样飞鸟,各从其类。神看着是好的。
——《旧约·创世纪》
第14章 消息:广义消息VS.狭义消息
曾是寂寥金烬暗,断无消息石榴红。
——李商隐,《无题》
第15章 模板方法模式:正向依赖VS.依赖倒置
乐思把他渗透了:有时是单独而完整的一句;更多的时候是包裹着整部作品的一片星云:曲子的结构,大体的线条,都在一个幕后面映现出来;幕上还有些光华四射的句子,在阴暗中灿然呈露,跟雕像一样分明。
——罗曼·罗兰,《约翰·克里斯朵夫》,卷四
第16章 MFC消息映射表模式:虚函数VS.映射表
人的生活就像作曲。各人为美感所导引,把一件件偶发事件(贝多芬的音乐,火车下的死亡)转换为音乐动机,然后,这个动机在各人生活的乐曲中取得一个永恒的位置。
——米兰·昆德拉,《生命中不能承受之轻》
第17章 适配器模式:类模式VS.对象模式
断鹤续凫,矫作者妄;移花接木,创始者奇。
——蒲松龄,《聊斋志异·陆判》
第18章 MVC模式:三国演义VS三分归一
天下大势,分久必合,合久必分。
——罗贯中,《三国演义》,第一回
第19章 C++编码经验谈:理论vs.实践
朱萨克,照当时的说法,是个剑法高手,而且已经身经百战;可是碰上这么一个压根儿不管通常的击剑规则,身子灵活、蹦蹦跳跳的对手,他反倒无所适从,不知如何招架是好了。
——大仲马,《三剑客》,第五章
自从2000年面向对象设计领域内的里程碑著作《设计模式》被译成中文出版后,面向对象和软件工程领域的经典名著就陆续被各出版社大批引进。模式、框架、UML、用例、MDA、AOP这些新潮名词开始不断出现在专业报刊杂志中,程序员的求职简历中也都纷纷加上了精通面向对象的字句,但一阵热潮过去后,开发者的实际设计水平提高了多少呢?很遗憾,从业界的实际反馈来看,一般开发者的面向对象设计水平并没有实质性的提高。
问题出在哪里呢?我们认为,关键在于经验。国外译著的理论水平很高,但是理论如何落实到实践,这是一个经验的问题。我们出版的技术图书当中,能够向读者传授实践经验的不多。图书市场上充斥了不少销售得还不错的软件开发案例丛书,它们本应当承担起教授读者实践经验的责任。但是它们的表现如何呢?大部分案例完全没有OO的设计思想,没有设计过程,没有重构,没有复用,重复代码到处出现,甚至还有不少错误的设计和代码。就是这样的图书,却能影响成千上万的学习者,这样学习下来的结果,当然不会令人乐观。
在软件开发的第一线人员中,OO的应用到底是什么样的景象呢?按实际应用的水平可以把软件开发人员分成五个层次:
第一层是不管什么OO,直接编码,把功能实现了项目就是成功;
第二层是理解了几个面向对象的典型概念——封装,继承,模式。囫囵吞枣,不管实际效率如何就开始应用,为OO而OO;
第三层是在设计阶段摆出一副OOAD的架子,进入编码实现就逐步把OO放到了一边,OO与实践分离;
第四层是基本掌握OO理论,在具体应用中能大量使用OO技术来进行系统分析和程序设计;
第五层是把OO思想融会贯通,不管用不用OO技术,都能选择最佳设计和实现方法。
我喜欢把设计模式类比成围棋定式,OO技术同样也可以类比成围棋技术。在围棋中定式的定义:“在局部战斗中,用最稳妥的顺序,而且能经得住以后的检验,从而被固定下来的就是定式”。
在软件开发中模式的定义:“将一类不断重复发生的,类似的问题以及该类问题的解决之道总结出此类问题的共同点并抽象成一定的描述及规范,以便遇到此类问题无须再做过多的考虑,直接使用已经总结好的解决之道。我们称之为模式”。
我们可以看到这两者的类似,围棋入门容易,精通难。抛开入门级别,围棋手按水平从业务初段到职业9段还可以划分16个等级,其差距就在于棋手们在实践中对技术的综合使用能力。
上面这几个层次的差别也在于此,要学习OO理论和方法并不难,难的是在实践中如何用好面向对象技术。OO大师们提出的理论和方法都有着深刻背景,剖析了软件开发过程,经过了提炼和抽象,大师们的名著是学习的基础,也有很多来源于实践的例子,但每个具体项目有着千差万别的情况,如果不能结合具体实践去灵活应用,可能很难达到较高的水平。
如果能跟踪学习一个完整项目的进展过程,对于在实践中全面掌握OO会有很大益处。
长久以来,我一直希望在《程序员》杂志上开设这样的栏目,针对真正的第一线实战项目,记录一个项目从分析到设计,并实现的思考全过程;类似于MBA教学中的案例分析,类似于围棋中的名局细解,从实践中去领悟体会OO技术的内涵。可是很困难,大部分的实践项目都不愿意完整地公开,另外,真正的专家高手又很难花时间去做这样的工作。
这本书弥补了这个遗憾,本书的作者有着多年丰富的软件开发经验,以一个真实的项目——FishGUI为基础,全面记录了项目的实施,并对每一个技术过程做了分析总结。凝聚了他们对OO技术的解读与实践,提炼出了经过咀嚼的精华。
读者可以跟着这个项目实施的步伐,从需求分析,用例建模,OO分析,OO系统设计,模式应用一步步去真实体验。书中精彩的部分包括对各种理论的提炼和解读,既讲清了这些纷繁技术的来龙去脉和关系,又点出了OO技术的关键点。华罗庚先生说过,读书要先把书读“厚”,再把书读“薄”。这些总结就是作者把OO技术读薄的成果。
“一花独放不是春”,只有不断交流,知识才能分享,技术才能进步,我衷心希望看到更多的第一线专家分享自己的成果,看到更多这样来源于实践的作品。
王咏武:在软件行业摸爬滚打十多年。大学四年,一直面对着裸露的单板机,一个
字节一个字节地调试各种不同的汇编语言;毕业后在UNIX系统下学了几年C和C++语
言,尝试开发了几个大型软件;随后又有机会在大型主机一人多高的CPU、硬盘以
及水管粗细的导线面前编写复杂的COBOL程序;最近几年则一直在移动通信领域奋
斗,在Solaris和Windows系统下开发、调试手机软件平台。现在已经不再狂热地追
寻各种新的语言或技术,而是把更多的精力放在了面向对象技术的应用层面上,并
特别关心面向对象技术在嵌入式系统中的应用问题。
王咏刚:职业程序员,业余撰稿人。在数据压缩、全文检索、内容管理、分布式系
统、软件测试等技术领域有一定的积累。撰写过一本据说还算有趣的技术读物《凌
波微步——软件开发警戒案例集》,协助微软亚洲研究院编写过《软件企业的管理
与文化》等技术书籍。曾在《程序员》、《CSDN开发高手》等杂志主持技术专栏,
在《中华读书报》等媒体发表书评文章若干,还以“王笨笨”的名义在网络上发布
过一些小有名气的技术教程。
我讨厌长篇大论的“前言”——为什么每一本严肃的图书都要用正文以外的篇幅浪费读者的大量时间?我也讨厌喋喋不休的“致谢”——IT书籍又不是奥斯卡颁奖典礼上的那些除了“感谢”二字就再也不知道如何谦虚的大牌明星。所以,大家在此处看到的前言只是一份简单的FAQ(常见问答,最有助于节省程序员时间的文档形式之一),读者完全可以像使用其他FAQ那样在这里快速查找自己需要的信息。
◇为什么需要一本面向实践的指南?
每1000个学习面向对象技术的程序员中,有997个都要将学到的知识付诸实践;在另外的3个人中,一个是只靠做研究和写论文就可以衣食无忧的理论家,另一个是试图记住800种以上的技术名词以便在人前炫耀的牛皮家,最后一个是根本不知道面向对象为何物却非要摆出头悬梁、锥刺股的架势博取老板欢心的钻营家。
显然,99.7%的人都需要在学习面向对象技术时,更多、更好地掌握理论和方法在实际项目中的应用秘诀。在此过程中,面向对象大师们的经典著作当然都是必读的教材。但实际工作中有太多太多的案例告诉我们,像赵括那样只会纸上谈兵的程序员迟早会在冷酷的现实中一败涂地。也许,一本面向实践的指南读物可以帮我们更快地适应面向对象的思维方式,更容易地将书本知识应用到实践中去——我们有什么理由拒绝这样一本实用的书籍呢?
◇谁需要这样一本指南?
绝大多数听说了也见过了面向对象的神奇魅力,却始终无法真正迈进面向对象大门的程序员需要这样一本指南;绝大多数在面向对象领域里刻苦攻读、努力实践,却迟迟不能看到美好回报的程序员需要这样一本指南;绝大多数在面向对象的开发过程中屡战屡败、灰心丧气,恨不得明天就去国足寻找同病相怜者的程序员需要这样一本指南;绝大多数对面向对象大师们的鸿篇巨著佩服得五体投地,却总也猜不出大师们在字里行间究竟隐藏了多少玄机的程序员需要这样一本指南;当然,绝大多数好奇心强烈,想了解本书到底有多大价值,想知道本书作者究竟是何许人也的评论者也不妨纡尊降贵,先读过本书再发表意见。
补充说明1:本书的读者最好能事先掌握一门面向对象的程序设计语言,C++、Java、C#、Delphi等语言均可。尽管本书案例使用的是C++语言,但大多数面向对象的语言都有着类似的精神实质,都能很好地体现本书的主旨。如果你对面向对象的程序设计语言还比较陌生,那不妨在阅读本书的同时学一学C++的语法和编码技巧——有这样一举两得的机会,你又何乐而不为呢?
补充说明2:如果了解UML语言的基础知识,阅读本书时,你就不会对着一堆堆抽象的图形发呆;如果还没有接触过UML语言,那不妨找一本《UML用户指南》之类的书籍,在阅读本书之余,趁便补习一下相关知识。
补充说明3:本书所说的“程序员”是指广义的程序员而言,包括所有在软件开发领域辛勤工作的开发人员、管理人员、系统分析人员、测试人员、技术支持人员等等。是否选择本书是读者的自由,但我们不想因为使用更亲切、更顺口的“程序员”一词而将许多潜在的读者拒之门外。
◇为什么要结合一个实际的案例?
这个问题纯属多余:一本自称面向实践的指南读物,如果不紧扣一个实际的开发案例,不就和《笑傲江湖》中林震南所使的辟邪剑法一样徒有其表了吗?
惟一需要说明的是,贯穿本书始终的案例——FishGUI项目(一个有趣的名字)是本书作者王咏武亲身参与的一个软件开发项目。无论项目的最终效果如何,我们从FishGUI的开发过程里获得的许多经验、教训都值得和大家分享。FishGUI产品本身属于通用的GUI(图形用户界面)框架系统,其用途类似于Java的Swing,但功能远比后者简单。因为强调通用性和灵活性的原因,这一类系统中往往包含了最多的面向对象知识和最丰富的开发技巧,用这样的例子来论证面向对象领域的基本理论和实践准则,再合适不过了。即便FishGUI的设计和实现还存在着诸多不足,但在书中把这样的例子详详细细展现出来,供方家指正,让读者品评,这不也是一种最好的交流方式吗?
◇为什么每章的标题都包含了一组对立统一的概念?
的确,本书正文中每一章的标题都包含了一组对立统一的概念。采用这种写法的主要原因是,我们对面向对象技术有一个最根本的认识:
面向对象领域充满了辩证关系,开发者不得不在每一个设计和实现环节中仔细权衡、则善而从。
许多急功近利的程序员都喜欢在开发时把某种技术、某种架构或某种设计方案的作用绝对化。在他们眼中,一种好的技术就理应放之四海而皆准,一种成功的设计方案也绝不存在什么适用场合和环境的问题。套用软件工程界广为流传的一个说法,这些人其实都是“银弹万能论”的忠实拥趸。
实际上,软件开发和所有人类活动一样,都是充满了矛盾的复杂过程。概括起来,绝大多数软件开发都是由一次又一次的选择所组成的:我们必须根据实际情况,谨慎地选择模型、选择架构、选择模式、选择语言、选择接口、选择流程、选择算法……每一次选择时,我们几乎都会面对两难的境地:对同一需求,往往有两种以上的方案可以奏效,但每一种方案都各有其长处、缺陷和适用范围。没有哪种技术完美无缺,也没有哪个负责任的程序员能够用掷硬币的方式做出取舍。
在面向对象的实践中,我们只有承认这种矛盾关系,才能更好地认识和把握它,并在对立统一的思辨中找到最适合当前情况的解决方案。从这个意义上讲,面向对象领域里那些游刃有余的高手们,都天生有着黑格尔般的敏锐头脑和缜密思路,都是IT世界里的业余哲学家。
◇如何阅读本书?
本书共分19章,依次介绍了需求和用例分析、面向对象分析、架构分析、面向对象设计、设计模式、编码技巧等几个主要的技术领域,并基本按照时间顺序,描述了FishGUI系统设计和实现的全过程。对于大多数以学习为目的的读者,我们推荐从头至尾、循序渐进的阅读方式;如果你对其中的某个或某几个领域早已了如指掌,当然可以采用跳跃式的阅读办法,只翻检你最关心的章节。
既然是一本面向实践的指南读物,我们在此强烈建议大家在阅读时多多动手:遇到不明白的UML图示,不妨在Rational Rose等工具中勾画几下;碰见繁难的代码问题,打开你的IDE调试本书的示例代码自然是最好的选择;假如在阅读过程中,你的脑子里突然跳出了某个新鲜的感觉,那你应该干净利落地把书抛在地上,然后飞快地跑到计算机前,在面向对象的开发工具中记录或验证你的灵感……
◇什么是“笨笨点评”?
本书大多数章节里都会随机出现一两段“笨笨点评”。这里的“笨笨”就是王咏刚,也就是那个慵懒闲散、不务正业、还时不时在报刊上发两篇笨拙文章的家伙了。所谓“点评”,就是王咏刚在整理和删改本书的过程中(本书的主要技术思想来自第一作者王咏武),因为大脑短路或其他类似的原因,突然想到并随手记下的各种稀奇古怪的文句,其中既有技术的随想,也有历史的回眸,既有肆意的评论,也有大胆的臆测。总之,大家千万别把“笨笨点评”当正文来读,高兴的时候尽管当它是下酒的凉菜,不高兴时对它视而不见也未尝不可。
◇为什么使用C++语言?
为什么不呢?C++语言是普及面最广、适用性最强、开发工具最多、开发成果最丰富的程序设计语言之一。既然本书的案例终归要由某种特定的程序设计语言来实现,那为什么不选择著名的C++呢?而且,现实中的FishGUI项目使用的就是C++语言,FishGUI的最终产品在执行效率、可扩展性、可移植性等方面的表现也都令人非常满意,我们有什么理由放弃C++语言呢?
我们知道,有人一定会说出C++太复杂、C++不如C#时髦等等冠冕堂皇的理由。我们不想为此多费口舌。但需要强调的是,在面向对象的领域里,只要你真正掌握了面向对象的基本理论和基本方法,使用何种语言对你来说并不重要。举例而言,如果你是不折不扣的Java迷,那你完全可以在阅读本书的同时,随着FishGUI的设计和开发的进程,用Java语言把FishGUI重写一遍,这可是一种最好的实践方式呀!到那时,如果你能把你的大作寄给我们学习和参考,我们将不胜荣幸。
◇FishGUI到底有什么用?
FishGUI系统是本书中最重要的开发案例,也是一个真实存在过的软件产品。很多在Windows或Linux系统中开发过GUI应用的读者可能大惑不解:既然已经有MFC、.NET Framework、AWT、Swing、SWT、Tcl/Tk、Qt等许多GUI开发环境可用,为什么还要自己开发FishGUI这样的GUI框架呢?我们觉得,除了为本书提供案例支持外,FishGUI的存在价值至少还包括以下几个方面:
我们可以很容易地将FishGUI移植到各种嵌入式或实时操作系统(RTOS)中。对于在那些缺乏GUI支持的操作系统中开发应用软件,或者没有实力购买商用GUI开发包的用户来说,FishGUI显然可以助他们一臂之力。
同样的道理,基于FishGUI开发的应用软件也可以快速移植到不同的嵌入式或实时操作系统中,并保持相同的外观和使用体验(Look and Feel)。
嵌入式软件开发者可以利用FishGUI在Windows或Linux系统下建立一个模拟开发环境,并在该模拟环境中利用Visual Studio等通用IDE快速完成图形用户界面的开发、调试工作,然后将应用程序不加修改地移植到嵌入式或实时操作系统中。
通过研习FishGUI系统的架构,我们可以更好地理解MFC、.NET Framework、AWT、Swing、SWT、Tcl/Tk、Qt等复杂GUI开发包的实现机理,这显然有助于提高我们的GUI开发水平。
◇怎样下载和使用本书的源代码?
本书各章节的源代码,FishGUI系统的所有UML模型文件、文档、源代码和相关说明文件都可以从网上直接下载。网址是: http://www.contextfree.net/wangyw/ooguide/你可以使用Rational Rose 2002或更高版本打开FishGUI系统的UML模型文件;在Windows系统下可使用Visual Studio .NET 2003或Visual C++ 6.0编译所有C++工程和源代码(Visual Studio .NET 2003也用于编译少量C#语言示例代码);在Unix/Linux系统下可使用gcc 3.2.2或更高版本编译C++工程和源代码。
有关FishGUI系统本身更详细的生成、安装和使用说明请参见本书附录及FishGUI源代码中所附的说明文档。