1999年春天,我飞抵芝加哥为ThoughtWorks公司正在开发的一个项目担任顾问。ThoughtWorks是一个规模虽小但正在快速成长的应用开发公司。这个项目属于那种雄心勃勃的企业级应用——一个后端租赁系统。简单说,它处理的是租户签字认可后所有与租赁有关的事务,包括发送账单、处理某些人对所租房产的改造、追踪那些未按时付款的租户、处理提前退租的情况等。这听起来好像并不太难实现,但是你大概没有意识到,租赁合同极度复杂并且总在不断变化。它的业务“逻辑”几乎不能套用任何已有的逻辑模式,因为那些“逻辑”归根到底是商人们为了抢生意而制定的,一些奇怪的小改动都可能对赢得某笔生意起关键作用。而每次这样的成功就意味着系统复杂性的增加。.
我感兴趣的正是这类问题:如何捕获这些复杂情况,并设计一个面向对象的系统使问题更容易解决。事实上,我认为面向对象的最大优点就在于它能够使复杂逻辑易于处理。为复杂业务问题开发一个好的领域模型(Domain Model,116)很困难,但结果往往非常令人满意。
但问题还没有完。我们的领域模型必须持久存储到数据库中,与许多项目一样,我们使用的也是关系数据库。我们还必须将该模型与用户界面连接起来,还要支持远程应用程序使用本软件,并将软件与第三方的软件包集成。所有这些工作都基于一种称作J2EE的新技术,当时世界上没有人在这方面具备真正的实战经验。
虽然J2EE当时还很新,但我们可以受助于以往的经验。我曾经使用C++、Smalltalk和CORBA开发类似系统已经多年。ThoughtWorks公司中许多人在Forte 方面有丰富经验。我们已经有了关键架构的思路,剩下的只是弄清如何用J2EE实现。三年后再来回顾,虽然设计并不完美,但却很好地经受住了时间的考验。
本书正是为这样的情形而撰写的。多年来,我见证了许多企业级应用项目。这些项目通常都包含相似的设计思路,事实证明这些设计思路可以有效地处理企业应用中不可避免的复杂性。本书就是将这些设计思路以模式形式表述的一个起点。
本书分为两个部分,第一部分是一些叙述性的章节,讨论企业级应用程序设计中的一些重要主题。这些章节介绍了企业级应用程序架构的各种问题及其解决方案,但解决方案的细节没有深入讨论。解决方案的细节是在本书的第二部分中以模式的方式组织起来的。这些模式都是参考,我并不希望读者逐页阅读。我的意图是,读者从头到尾将第一部分的叙述性章节读完,然后再根据兴趣和需求浏览第二部分的模式章节。因此,本书实际上是一本简短的叙述图书和详尽的参考书的二合一。
本书讨论的是企业级应用程序的设计。企业级应用程序涉及大量复杂数据的显示、操作和存储以及对这些数据进行处理的业务流程的自动化。典型的例子有预订系统、财务系统、供应链系统以及许多其他支持现代商业运作的系统。企业级应用和嵌入式系统、控制系统、电信系统或者桌面应用软件不同,它们有自己特有的难度和解决方案。因此,如果你从事的是上述那些非企业领域的工作,那么本书不适合你(除非想体会一下企业级应用程序是怎么一回事)。如果需要一本关于软件架构的通用书,我推荐[POSA]。
在构建企业级应用时有许多架构方面的问题。本书恐怕无法面面俱到。在软件开发方面,我一直坚信迭代开发方法。迭代开发的核心在于只要软件具备了用户可用的功能,就应当交付,即使软件并未完成。虽然著书与编写软件之间存在很多差异,但在这一点上我认为是相通的。也就是说,虽然本书尚不全面,但(我相信)可以为读者提供有关企业级应用程序架构方面的有益建议。本书讨论的主题包括:
企业级应用程序的分层;
构建领域(业务)逻辑;
构建Web用户界面;
将内存中的模块(特别是对象)与关系数据库关联起来;..
处理在无状态环境下的会话状态;
分布的原则。
本书尚未涉及的主题更多。我很想撰写关于验证的组织、消息和异步通信的加入、安全、错误处理、集群、应用集成、架构重构、构建富客户用户界面等方面的书籍或文章。但是,由于时间和篇幅的限制以及想法尚不成熟,本书没有涉及上述内容。我希望在不久的将来能看到这方面的模式。也许我会撰写另一本书讨论这些内容,或者会有其他人来弥补这一缺憾。
其中基于消息的通信是相当重要的问题。从事多应用程序集成的开发者正越来越多地用到异步的、基于消息的通信方法。在应用程序内部的应用也有很多内容需要探讨。
本书并不针对特定的软件平台。从20世纪80年代末到90年代初,我开始在Smalltalk、C++和CORBA项目中使用这些模式。而20世纪90年代后期我开始在Java方面做大量的工作,我发现这些模式可以很好地应用于较早的Java/CORBA系统和其后基于J2EE的开发。最近,我开始探索微软的.NET平台,发现这些模式同样有效。ThoughtWorks公司的同事也介绍了他们的经验,尤其是Forte方面。我不敢说这些模式能够适用于所有已经和即将用于企业级应用的开发平台,但到目前为止,它们显示出足够的适用性。
本书为大多数模式提供了代码示例。选择程序设计语言时主要考虑大多数读者都能够阅读和理解。Java就是一个很好的选择。任何人只要能阅读C或C++代码就可以读懂Java代码,Java比C++简单得多。大多数C++程序员都能够理解Java,但反过来却并非如此。我偏爱面向对象,当然倾向于使用面向对象语言。因此,大多数代码示例使用的是Java语言。写作本书时,微软的.NET环境逐渐稳定,它的C#语言与Java有许多相同之处。所以某些代码示例也使用了C#语言,虽然这样做会多少有一些风险,因为大多数开发者没有太多.NET经验,所以所用的惯用法并不成熟。这两种语言都基于C,因此只要能阅读其中一种,就算对另一种语言或平台没有深入研究,也能阅读。我的目的是使用一种能够让最多的软件开发者阅读的语言,虽然这并非他们主要使用或爱用的语言。(谨向那些喜欢Smalltalk、Delphi、Visual Basic、Perl、Python、Ruby、COBOL或其他语言的读者致歉。我知道你们认为有比Java或C#更好的语言,我只能说我也认为如此!)
示例是用来阐述和解释模式思想的。它们并非可以直接使用的解决方案,任何情况下还需要做不少工作才能应用它们。模式只是有益的起点,不是终点。
本书面向的读者
.本书面向的是正在构建企业级应用,希望增进对架构相关问题的理解,加强此方面沟通的程序员、设计师和软件架构师。
我假定本书的大多数读者可以归为两类:一些人所面临的需求规模不大,计划自己构建软件;另一些人面临的需求较多,需要使用某些工具。对于较小规模的需求,本书提及的模式将有助于着手工作。尽管在许多领域,所需的知识超出了本书的内容,但本书能够提供先发优势。对于工具使用者,我希望本书能揭示工具背后的一些技术内幕,帮助他们决策如何选择工具所支持的模式。例如,使用对象-关系映射工具时,你仍然必须决定如何映射某些特定情况。本书所提供的模式将有助于做出这样的决策。
此外,还存在第三类读者,他们有较多需求,又要自己构建软件。在此,我要说的是:请先考虑是否使用工具。我已经见过不止一个项目花费大量时间来建造框架,而这些框架并非该项目所真正要解决的问题。当然,如果确认没有问题,那请继续好了。请记住,为提高可理解性,本书中许多代码示例都有意简化了,你会发现需要做很多工作来处理所面临的更多需求。
由于模式是对不断出现的问题的通用解决方案,因此很可能有的读者已经遇到过当中的一些模式了。如果你从事企业级应用开发已经有一段时间,可能会很熟悉其中大部分模式。本书中并不包含任何新的东西,正相反,这是一本讲述(我们这一行业的)既有知识的书。如果你是这一领域的新手,我希望本书将帮助你学习这些技术。如果你熟悉这些技术,我希望本书有助于你与其他人沟通。模式的重要作用就在于其创建了一个通用的词汇表,例如,你称某个类是远程外观(Remote Facade,388),其他设计人员就都知道你指的是什么。
致谢
与其他书籍一样,这里将涉及多年来以不同方式与我一起工作的很多人。他们以许多方式对我提供过帮助。本书中一些重要内容是由他人提供的,其中某些人我可能已经无法回忆起他们的名字。在这里,我所能做的是对那些仍铭记在心的人表示感谢。
首先要感谢的是我的合作者,David Rice,他是我在ThoughtWorks公司的同事,他为本书做出了巨大的贡献:撰写了本书的1/10以上的内容。当我们一起努力以保证本书能如期交稿时(他当时还要从事客户支持的工作),我们曾在若干个深夜通过即时消息软件进行协商,交谈中他坦承他总算明白了为何写一本书是如此困难却又如此吸引人。
Matt Foemmel是我在ThoughtWorks公司的另一个同事。他为代码示例做出了很大的贡献。Randy Stafford为本书贡献了服务层(Service Layer,133),他一直是此模式的极力倡导者。我还要感谢Edward Hieatt和Rob Mee所做的贡献,Rob在审阅本书时发现了一个漏洞。Rob是我的最佳审稿人:他不仅发现少了某些内容,而且他还帮我写了一节来弥补这个漏洞!
同样,对本书一流的正式审稿人,我的言辞远不能表达我的感激之情:
John Brewer、Rob Mee、Kyle Brown、Gerard Meszarios、Jens Coldewey、Dirk Riehle、John Crupi、Randy Stafford、Leonard Fenster、David Siegel、Alan Knight、Kai Yu。
我几乎要把ThoughtWorks公司的电话号码本列全了,因为有太多的同事与我讨论他们的设计和经验,助我完成这一项目。许多模式在我脑中成型,是因为我有机会与众多天才设计师讨论,因此我只好对整个公司表示感谢。
Kyle Brown、Rachel Reinitz和Bobby Woolf在百忙之中抽出时间与我一道在北卡罗莱纳对本书进行了长期而细致的审阅。他们的批评指正为本书注入了各种睿智之见。尤其是与Kyle的几次长时间的电话交谈令我获益匪浅。
2000年初我与Alan Knight和Kai Yu一起为Java One大会准备了一个演讲,这是本书的雏形。我还要感谢Josh Mackenzie、Rebecca Parsons和 Dave Rice,他们其后协助我提炼了这些演讲及其思想。Jim Newkirk付出了很大努力来帮助我熟悉.NET平台。
我与这个领域的许多专家有过令人愉快的交谈或合作,我从他们那里获益匪浅。这里尤其要对Colleen Roe、David Muirhead和Randy Stafford表示感谢,他们将自己在Gemstone的Foodsmart示例系统上的工作成果与我共享。我参加了Bruce Eckel所主持的Crested Butte讨论会的一些重要会谈,向近年来这一会议的与会者致谢。Joshua Kerievsky虽然没有时间对本书做一次全面的审阅,但他是我在模式方面很好的顾问。
我一如既往地从伊利诺斯大学阅读组独特的不闭门评审会得到了极大的帮助。我要感谢:Ariel Gertzenstein、Bosko Zivaljevic、Brad Jones、Brian Foote、Brian Marick、Federico Balaguer、Joseph Yoder、John Brant、Mike Hewner、Ralph Johnson和Weerasak Witthawaskul。
伊利诺斯大学的毕业生Dragos Manolescu及其小组给我提供了不少反馈意见。感谢Muhammad Anan、Brian Doyle、Emad Ghosheh、Glenn Graessle、Daniel Hein、Prabhaharan Kumarakulasingam、Joe Quint、John Reinke、Kevin Reynolds、Sripriya Srinivasan和Tirumala Vaddiraju。
Kent Back为我提供了许多思路。是他为特殊情况(Special Case,496)模式起了名字。Jim Odell将我领入了咨询、教学和写作的世界,我由衷地感谢他。
当我写这本书时,曾将草稿放在网上。期间许多人通过电子邮件向我指出问题、提出疑问或者讨论其他替代方案。他们中有Michael Banks、Mark Bernstein、Graham Berrisford、Bjorn Beskow、Bryan Boreham、Sean Broadley、Peris Brodsky、Paul Campbell、Chester Chen、John Coakley、Bob Corrick、Pascal Costanza、Andy Czerwonka、Martin Diehl、Daniel Drasin、Juan Gomez Duaso、Don Dwiggins、Peter Foreman、Russell Freeman、Peter Gassmann、Jason Gorman、Dan Green、Lars Gregori、Rick Hansen、Tobin Harris、Russel Healey、Christian Heller、Richard Henderson、Kyle Hermenean、Carsten Heyl、Akira Hirasawa、Eric Kaun、Kirk Knoernschild、Jesper Ladegaard、Chris Lopez、Paolo Marino、Jeremy Miller、Ivan Mitrovic、Thomas Neumann、Judy Obee、Paolo Parovel、Trevor Pinkney、Tomas Restrepo、Joel Rieder、Matthew Roberts、Stefan Roock、Ken Rosha、Andy Schneider、Alexandre Semenov、Stan Silvert、Geoff Soutter、Volker Termath、Christopher Thames、Volker Turau、Knut Wannheden、Marc Wallace、Stefan Wenig、Brad Wiemerslage、Mark Windholtz、Michael Yoon。
此外,还有许多我不认识或已经遗忘了的人,在此致以真诚的谢意。
最诚挚的谢意依旧要献给我的妻子Cindy,感谢她一直陪伴左右。...