如果我已经有了第1版,还需要买第2版吗?
回答当然是“需要”!原因如下。
自完成第1版的写作之后,我们对设计模式又有了大量更深入的理解,包括以下一些方面。
如何使用共性和可变性分析来设计应用程序的架构。
设计模式与极限编程(eXtreme programming,XP)和敏捷开发的关系,以及设计模式
如何有助于二者的实施。
为什么测试是高质量编程的一个优先原则。
为什么使用工厂(factory)实例化和管理对象至关重要。
对帮助学生理解如何用模式思考而言,哪些模式是必不可少的。
本书探讨了所有这些主题。我们进一步深化和澄清了前一版阐述过的主题,并增加了一些非常有用的新内容,包括:
第15章,共性和可变性分析;
第20章,来自设计模式的教益:各种工厂模式;
第22章,ObjectPool模式(《设计模式》一书中没有讨论的模式);
第24章,工厂模式的总结。
我们改变了一些模式的阐述顺序,据参加该课程的学生反映,这样的顺序更有助于掌握模式背后的思想。
所有章节的内容都进行了少量修改,综合了过去三年来从许多读者那里收到的各种反馈意见。而且,为了帮助学生学习,我们为每一章都编写了复习题(答案在本书配套网站可以找到)。
我们可以非常坦率地说,本书无疑是少数值得拥有的第2版,即使读者已经购买了第1版。
非常乐于倾听您宝贵的建议。
——Alan和Jim
设计模式和面向对象程序设计曾经做出过这样的承诺:要简化软件设计人员和开发人员的工作。技术媒体甚至大众媒体每天都在传播相关的术语。然而,要学习这两种技术,熟练掌握它们并且知其所以然,可能非常困难。
. 你使用某种面向对象或者基于对象的语言可能已经多年,可你是否知道,对象真正的威力并不在于继承,而是来自封装行为。你可能对设计模式很好奇,而且感觉相关的著作都有些太过深奥和夸张。倘若如此,本书正适合你。
本书是以作者多年来为许多软件开发人员(包括面向对象技术老兵和新手)讲授模式的经验为基础撰写而成的。我们相信,而且我们的经验也已经证明,如果能够理解模式背后的基本原则和动机,理解它们为什么会这样运作,那么你的学习曲线将不可思议地缩短。而且在我们对设计模式的讨论中,可以懂得真正的面向对象思维定式,这正是登堂入室的必由之路。
通过阅读本书,读者能够完整地理解12个核心设计模式和1个分析模式,也将了解到设计模式并不是孤立存在的,多个设计模式协同工作才能帮助我们创建更加“健壮”的应用程序。你还可以获得阅读其他设计模式文献所需的足够基础知识,如果愿意,可能还能够自己发现新的模式呢。最重要的是,你将为创建灵活、完善而且更易维护的软件做好准备。
虽然这里所讲授的12个模式并没有涵盖所有应该学会的模式,但是理解了这12个模式,就能够举一反三,更加容易地自学其他模式。我们没有讨论入门所需之外的更多模式,而是讲述了更加有用的与模式相关的若干问题。
从面向对象到模式再到真iE的面向对象
从很多方面来看,本书实际上是在复述我自己学习设计模式的经历。我是在学习模式本身之后,再学习模式背后的思想。然后,又将这种理解扩展到分析和测试领域,也扩展到学习模式与敏捷编程方法的关系中。本书第2版中包含了许多第1版出版后我的一些领悟。在学习设计模式之前,我自认为已经是一个很不错的面向对象分析和设计专家了,我曾经设计和实现了几个针对许多不同行业的非常出色的项目。我使用C抖并且正在学习Java,代码中的对象可以说是中规中矩、封装严密,而且还能为继承层次结构设计出优秀的数据抽象。我想自己应该已经得面向对象之道了。
现在回想起来,我发现自己那时虽然总是遵循大多数专家的建议行事,但是并没有真正理解面向对象设计的全部威力。直到开始学习设计模式,我的面向对象设计能力才得以拓展和加强。即使还没有直接使用模式,理解设计模式也已经使我成为更加出色的设计人员。
我开始学习设计模式是在1996年。那时我还是美国西北部一家大型航天公司的一名C++和面向对象设计讲师。有几个人要求我领导一个设计模式学习小组,正是在那里我遇到了本书的另一位作者Jim Trott。学习小组中发生的几件事情很有意思。一开始,我就对设计模式着了迷。我很喜欢能够将自己的设计与其他经验更多的人的设计进行比较。然后,我就发现自己并没有发挥“按接口设计”(designing to interface)的全部威力,而且并不总是关注是否存在“—个对象在还不知道另一个对象的类型时就使用这个对象”的情况。我还注意到,刚刚从事面向对象设计的人(一般总是认为这时就学习设计模式过早)从学习小组所得的获益,居然同专家差不多。设计模式展示了优秀的面向对象设计实例,而且阐明了基本的面向对象设计原则,这些有助于初学者更快设计出成熟的方案。到整个学习结束时,我已经完全相信:设计模式是面向对象设计发明以来软件设计领域出现的最伟大的东西。
可是,在我审视当时自己的工作时,却看到代码中并没有使用任何设计模式。或者说,至少还没有有意识地使用任何一个模式。后来,随着对模式学习的深入,我发现自己开始在代码中使用许多设计模式了,不再仅仅是一个好的编程匠。当然,现在我对模式的理解更加深入,使用起它们来也更加得心应手了。
我当时只是觉得自己可能对设计模式还了解得不够,应该学习更多。那时我只了解其中6个模式。然后,我突然顿悟。当时我是一个项目的面向对象设计顾问,而且应要求为项目做高层设计。这个项目的负责人极为聪明,但在面向对象设计方面却是一个新手。
问题本身并不怎么难,但是对代码维护性的要求很高。我花两分钟查看了一下问题,然后就照本宣科地按照通常使用的数据抽象方法提出了一个设计。很不幸,我自己也清楚这不会是什么好的设计。只用数据抽象使我无功而返,必须另寻良策。
两个小时之后,我用尽了自己知道的所有设计技术,已经黔驴技穷,情况却毫无好转的迹象。我的设计没有本质上的变化。最让人感到灰心的是,我知道肯定有更好的设计方案,只是我想不出来。更具讽刺意味的是,我还知道这个问题里藏着4个设计模式,可是我不知道怎么使用。于是,我——一个自封的面向对象设计专家,被一个简单问题生生噎住了!
我感到失望之极,只好休息一下,出去走走,清醒清醒头脑。我告诉自己,至少10分钟之 内不要再想这个问题了。可是,才过30秒钟,我就忍不住又思考起来!这次我突生灵感,刹那 间,自己的设计模式观改变了:不能将模式作为一个单独的东西使用,应该把它们结合起来。
模式应该相互配合,共同解决问题。
这话以前我也听说过,但是当时并没有真正理解。因为软件中的模式最初以设计模式为名引 入,我想当然地认为它们主要都是关于设计的,并一直囿于这样的想法而碌碌无为。我曾认为, 在设计领域,模式就是类之间合乎规则的关系。后来读到Christopher Alexander的奇书The Timeless Way of Building(牛津大学出版社,1979),我才知道所有层次——分析、设计和实现都存在模 式。Alexander曾阐述了使用模式有助于理解问题域(甚至有助于描述它),而不仅仅是用来在理解问题域之后完成设计。
我错就错在试图在问题域中创建类,然后再将它们结合起来形成一个系统,这正是Alexander所说的非常糟糕的做法。我从没有自问过这些类是否正确,因为它们看上去很好,显而易见,类从一开始分析就马上浮现于我的脑海,而且它们正是按教科书一直教的那样应该在系统描述中寻找的那些“名词”。但是试图将它们组合起来时却遇到了重重困难。
当我再回到办公室,在设计模式和Alexander方法的指导下重新创建类时,仅仅几分钟时间,一个大为改观的解决方案就展现出来。这真是一个好设计,我们最后根据它实现了产品。我真的很兴奋——兴奋于自己设计了如此优秀的方案,也兴奋于设计模式的威力。从那时起,我开始将设计模式融入开发工作和教学中。
我发现,不熟悉面向对象设计的程序员也可以学习设计模式,而且,通过学习设计模式,他们能够掌握基本的面向对象设计技术。对我而言就是如此,对我教授的学生而言亦然。
想象一下我是多么惊讶吧!我曾经读过的设计模式图书,曾经与之交谈过的设计模式专家都说,在开始设计模式研究之前,需要扎扎实实地打好面向对象设计基础。可是,我自己的亲身经验却表明,在学习面向对象设计的同时学习设计模式的学生,比仅仅学习面向对象设计的学生,进步更快,他们掌握设计模式的速度甚至与有经验的面向对象老手一样。
我开始使用设计模式作为自己教学的基础,并且将自己的课程称为“面向模式的设计:设计模式从分析到实现”。
我希望我的学生能理解这些模式,继而可以发现使用一种探索式的方法是有助于促进这种理解的最佳方式。例如,我发现,先提出问题,然后通过大多数模式中都适用的一些指导性原则和策略,帮助学生尝试为此问题设计出解决方案,这样阐述Bridge(桥接)模式更好。在实际探索中,学生找到了解决之道——其实就是Bridge模式,并牢牢地记在心中。
设计模式与敏捷方法/极限编程
设计模式之下所隐藏的指导性原则和策略现在对我而言已经非常清楚了。《设计模式》一书中肯定提到了这些内容,但是讲得太简洁,以至于我第一次阅读时完全没有体会到其价值。我相信《设计模式》一书实际上是以Smalltalk社区为目标读者而写的Q),这些原则在Smalltalk社区可以说是根深蒂固,所以不需要太多背景。但是因为自己对面向对象范型的理解很有限,我理解这些原则花了很长时间。直到我将《设计模式》四位作者的工作与Alexander的工作、Jim Coplien关于共性和可变性分析的工作、Martin Fowler关于方法学和分析模式的工作结合起来之后,这些原则对我而言才变得足够清晰,我甚至能够向其他人讲解。这对我自己的教学生涯也很有帮助——我再也不能像自己工作时那样容易地想当然,而又能侥幸无事了。
自本书第1版出版以来,我一直在进行大量的敏捷开发实践,具有了较多的极限编程实践、测试驱动开发(TDD)和Scram的经验。刚开始,在结合设计模式和极限编程、测试驱动开发时还是经历了一段困难时期。但是,我很快认识到它们都非常重要,而且植根于一些相同的原则(虽然设计方法并不相同)。事实上,在敏捷软件开发训练课上,我明确说明,如果正确使用设计模式将为引入敏捷开发打下很好的基础。
贯穿本书始终,我讨论了许多设计模式与敏捷管理和编程实践的关联。如果读者对极限编程、测试驱动开发或者Scrum不熟悉,可以不用太在意这些论述。但是,如果真的如此,我建议你下一步就去读一本有关的著作。
我发现无论何种情况下,都可以用这些指导性原则和策略来“推导”出几个设计模式。这里“推导出设计模式”的意思是,如果看到可能用设计模式解决的问题,就可以使用从模式中学到的这些指导性原则和策略,得到以模式表达的解决方案。我明确地告诉学生们,我们并不是用这种方法真正得出设计模式;相反,我只是要说明一种可能的思考过程,最终成为设计模式的那些解决方案的提出者使用的也是这样的过程。
我解释这些数量不多但很强大的原则和策略的能力与日俱增。随之而来的,是我发现自己解释《设计模式》一书中的模式时,它们更加有用了。事实上,我在设计模式课上用这些原则和策略能够阐述几乎所有的模式。
我还发现,无论是否使用设计模式,自己在设计中都在使用这些原则。我对此并不感到惊讶。如果使用这些原则和策略能够得到后来才发现等效于设计模式的设计,那么就说明这些原则和策略已经给了我一种自己做出优秀设计的方法(因为根据定义,模式代表着优秀设计)。有了这些技术难道还会只是因为不知道对应模式(可能已知也可能还没有发现)的名字而得出较差的设计吗?
这些认识帮助我很好地磨砺了自己的培训过程(和现在的写作)。我现在的教学工作已经有了好几个层次。教授面向对象分析和设计基础时,我教设计模式,并用它们作为优秀面向对象分析和设计的例子。此外,通过设计模式来教授面向对象概念,学生们还能更好地理解面向对象原则。而且教授指导性原则和策略,使学生们可以自己创建出质量能够与模式媲美的设计。
在此讲述这些,是因为本书正是沿袭了我所教授课程的模式,几乎所有的材料就是我们目前的课程之一——“设计模式、测试驱动开发或者敏捷开发最佳实践”的内容。
通过阅读本书,你将学习到这些模式。但尤其重要的是,你将学到模式为何有效和如何协同工作,以及模式背后的原则和策略,这将有助于充分利用你自身的经验。当本书提出一个问题时,如果你能够联想到——个曾经碰到的类似问题,将极其有益。本书并没有讲述什么新知识或者如何应用新模式,而是提供了一种考虑面向对象软件开发的新视角。我希望你的自身经验能够与设计模式的原则结合,成为学习过程中强大的助力。
Alan Shalloway
2000年12月第1版
2004年10月第2版