本书开创性地深入揭示了重构与模式这两种软件开发关键技术之间的联系,说明了通过重构实现模式改善既有的设计,往往优于在新的设计早期使用模式。本书不仅展示了一种应用模式和重构的创新方法,而且有助于读者结合实战深入理解重构和模式。书中讲述了27种重构方式。\r\n 本书适于面向对象软件开发人员阅读,也可作为高校计算机专业、软件工程专业师生的参考读物。
第1章 本书的写作缘由 1\r\n1.1 过度设计 1\r\n1.2 模式万灵丹 2\r\n1.3 设计不足 2\r\n1.4 测试驱动开发和持续重构 3\r\n1.5 重构与模式 5\r\n1.6 演进式设计 6\r\n\r\n第2章 重构 7\r\n2.1 何谓重构 7\r\n2.2 重构的动机 8\r\n2.3 众目睽睽 9\r\n2.4 可读性好的代码 10\r\n2.5 保持清晰 11\r\n2.6 循序渐进 11\r\n2.7 设计欠账 12\r\n2.8 演变出新的架构 13\r\n2.9 复合重构与测试驱动的重构 13\r\n2.10 复合重构的优点 15\r\n2.11 重构工具 15\r\n\r\n第3章 模式 17\r\n3.1 何谓模式 17\r\n3.2 模式痴迷 18\r\n3.3 实现模式的方式不止一种 20\r\n3.4 通过重构实现、趋向和去除模式 22\r\n3.5 模式是否会使代码更加复杂 24\r\n3.6 模式知识 25\r\n3.7 使用模式的预先设计 26\r\n\r\n第4章 代码坏味 29\r\n4.1 重复代码(Duplicated Code) 31\r\n4.2 方法过长(Long Method) 31\r\n4.3 条件逻辑太复杂(Conditional Complexity) 32\r\n4.4 基本类型迷恋(Primitive Obsession) 33\r\n4.5 不恰当的暴露(Indecent Exposure) 33\r\n4.6 解决方案蔓延(Solution Sprawl) 34\r\n4.7 异曲同工的类(Alternative Classes with Different Interfaces) 34\r\n4.8 冗赘类(Lazy Class) 34\r\n4.9 类过大(Large Class) 34\r\n4.10 分支语句(Switch Statement) 35\r\n4.11 组合爆炸(Combinatorial Explosion) 35\r\n4.12 怪异解决方案(Oddball Solution) 35\r\n\r\n第5章 模式导向的重构目录 37\r\n5.1 重构的格式 37\r\n5.2 本目录中引用的项目 38\r\n5.2.1 XML Builder 39\r\n5.2.2 HTML Parser 39\r\n5.2.3 贷款风险计算程序 40\r\n5.3 起点 40\r\n5.4 学习顺序 41\r\n\r\n第6章 创建 43\r\n6.1 用Creation Method替换构造函数 44\r\n6.1.1 动机 44\r\n6.1.2 做法 46\r\n6.1.3 示例 46\r\n6.1.4 变体 51\r\n6.2 将创建知识搬移到Factory 52\r\n6.2.1 动机 53\r\n6.2.2 做法 55\r\n6.2.3 示例 56\r\n6.3 用Factory封装类 61\r\n6.3.1 动机 62\r\n6.3.2 做法 63\r\n6.3.3 示例 63\r\n6.3.4 变体 66\r\n6.4 用Factory Method引入多态创建 68\r\n6.4.1 动机 68\r\n6.4.2 做法 69\r\n6.4.3 示例 71\r\n6.5 用Builder封装Composite 74\r\n6.5.1 做法 76\r\n6.5.2 示例 77\r\n6.5.3 变体 87\r\n6.6 内联Singleton 90\r\n6.6.1 动机 90\r\n6.6.2 做法 92\r\n6.6.3 示例 93\r\n\r\n第7章 简化 97\r\n7.1 组合方法 98\r\n7.1.1 动机 98\r\n7.1.2 做法 100\r\n7.1.3 示例 100\r\n7.2 用Strategy替换条件逻辑 103\r\n7.2.1 动机 103\r\n7.2.2 做法 105\r\n7.2.3 示例 106\r\n7.3 将装饰功能搬移到Decorator 115\r\n7.3.1 动机 115\r\n7.3.2 做法 119\r\n7.3.3 示例 120\r\n7.4 用State替换状态改变条件语句 134\r\n7.4.1 动机 134\r\n7.4.2 做法 135\r\n7.4.3 示例 136\r\n7.5 用Composite替换隐含树 144\r\n7.5.1 动机 144\r\n7.5.2 做法 147\r\n7.5.3 示例 148\r\n7.6 用Command替换条件调度程序 155\r\n7.6.1 动机 156\r\n7.6.2 做法 157\r\n7.6.3 示例 158\r\n\r\n第8章 泛化 165\r\n8.1 形成Template Method 166\r\n8.1.1 动机 167\r\n8.1.2 做法 168\r\n8.1.3 示例 168\r\n8.2 提取Composite 173\r\n8.2.1 动机 173\r\n8.2.2 做法 174\r\n8.2.3 示例 175\r\n8.3 用Composite替换一/多之分 181\r\n8.3.1 动机 181\r\n8.3.2 做法 183\r\n8.3.3 示例 184\r\n8.4 用Observer替换硬编码的通知 191\r\n8.4.1 动机 191\r\n8.4.2 做法 192\r\n8.4.3 示例 193\r\n8.5 通过Adapter统一接口 200\r\n8.5.1 动机 200\r\n8.5.2 做法 201\r\n8.5.3 示例 202\r\n8.6 提取Adapter 209\r\n8.6.1 动机 209\r\n8.6.2 做法 211\r\n8.6.3 示例 211\r\n8.6.4 变体 217\r\n8.7 用Interpreter替换隐式语言 218\r\n8.7.1 动机 218\r\n8.7.2 做法 220\r\n8.7.3 示例 221\r\n\r\n第9章 保护 231\r\n9.1 用类替换类型代码 232\r\n9.1.1 动机 232\r\n9.1.2 做法 234\r\n9.1.3 示例 235\r\n9.2 用Singleton限制实例化 240\r\n9.2.1 动机 240\r\n9.2.2 做法 241\r\n9.2.3 示例 241\r\n9.3 引入Null Object 243\r\n9.3.1 动机 244\r\n9.3.2 做法 245\r\n9.3.3 示例 246\r\n\r\n第10章 聚集操作 251\r\n10.1 将聚集操作搬移到Collecting Parameter 252\r\n10.1.1 动机 252\r\n10.1.2 做法 253\r\n10.1.3 示例 254\r\n10.2 将聚集操作搬移到Visitor 258\r\n10.2.1 动机 258\r\n10.2.2 做法 262\r\n10.2.3 示例 266\r\n\r\n第11章 实用重构 273\r\n11.1 链构造函数 274\r\n11.1.1 动机 274\r\n11.1.2 做法 275\r\n11.1.3 示例 275\r\n11.2 统一接口 277\r\n11.2.1 动机 277\r\n11.2.2 做法 278\r\n11.2.3 示例 278\r\n11.3 提取参数 279\r\n11.3.1 动机 279\r\n11.3.2 做法 279\r\n11.3.3 示例 280\r\n\r\n跋 281\r\n参考文献 283\r\n索引 287
设计模式和重构对我们来说早已不是什么陌生的字眼了。1994年,GoF的巨著《设计模式》初次向世人展示了设计模式的魅力。2002年,Martin Fowler的《重构:改善既有代码的设计》则刮起了一阵重构的旋风。记得在《重构》刚刚出版的时候,软件开发界和评论界就赞扬它是一本具有与《设计模式》同等高度的图书。我相信本书的每一位读者都和我一样,早已收藏了这两本书,反复阅读,仔细品味,并从中获益匪浅。
设计模式代表了传统软件开发的思想:好的设计会产生好的软件,因此在实际开发之前,值得花时间去做一个全面而细致的设计。而重构则代表了敏捷软件开发的浪潮:软件并不是在一开始就可以设计得完美无缺的,因此可以先进行实际开发,然后通过对代码不断地进行小幅度的修改来改善其设计。这两种方式看似格格不入,但是它们都在本质上有一个相同的思想——设计很重要,只是两者达到良好设计的方法不同。从设计模式和重构第一天与开发人员见面开始,它们就注定是一对休戚相关的兄弟。现在,本书终于为人们架设了一道连接设计模式与重构的桥梁。
这段时间,我总在想这样一个问题:什么是设计模式?每一类编程语言都具有其自身的特性,就面向对象编程语言来说,其特性就是抽象、封装、继承和多态。同时,使用每一类编程语言开发软件时也都有一些设计准则,这些准则保证了软件的质量,即具有良好的设计。而设计模式则是广大软件开发人员总结出的开发经验和技巧,它们利用编程语言的特性,实现这些设计准则。因此,在有经验的软件设计师眼里,没有设计模式,只有设计准则。现在,本书作者告诉我们:重构是实现设计模式的一种手段,设计模式往往也是重构的目的。从某种意义上来说,重构成全了设计模式,而设计模式度量了重构。需要注意的是,所谓“设计模式是重构的目的”,并不是说重构的结果一定是设计模式,有些情况下,重构恰恰是为了避免设计模式的过度使用。这是本书最值得关注的地方。
在准备写这篇译者序的时候,我总是觉得很为难,因为写译者序类似于写读后感,是要道出翻译过程中的特别感受,而我在翻译的过程中并没有什么特别突兀的触动。从本书的第一个重构直到最后一个,一切都显得那么自然;作者给出的每一个建议,每一个告诫,每一次小小的改动,给我的感觉都是水到渠成的。现在想想,其实重构的魅力就在于此,它就是每个软件开发人员自然而然应该做的事情。有句话叫“绚烂之极归于平淡”,用来形容重构,真是再合适不过了。
翻译从来就不是一件轻松的事,加之我完成本书翻译的日子都是在上海炎热的夏天中度过的。每当我汗流浃背地坐在电脑前,斟酌应该如何表达作者原意的时候,我都会从作者迸发的思维和精巧的话语中感受到一种平淡而又无穷的智慧。有趣的是,我接受本书翻译邀请的那天,Martin Fowler先生正好到上海做演讲,能在这位《重构》作者的演讲堂上接受到一本重构图书的翻译邀请,真是机缘巧合。
最后,我要谢谢我的父母。是他们给了我一个健康的身体,一个良好的生活环境,更重要的是全心全意的支持。没有他们就没有这一切。爸爸妈妈,我爱你们。
译 者
2006年8月25日
Joshua Kerievsky,资深软件设计师,软件开发公司Industrial Logic的创始人,是年轻一代软件开发方面最具人气的专家之一。他曾为许多专业杂志撰稿,并多次在世界级技术会议上担任讲师。除本书外,他还参加撰写了Extreme Pro-gramming Explored和Extreme Programming Perspectives。
本书主旨
本书讲述的是重构(改善既有代码设计的过程)与模式(针对反复出现的问题的经典解决方案)的结合。本书建议,使用模式来改善既有的设计,要优于在新的设计早期使用模式。这对于已经存在几年和几分钟的代码都同样适用。我们通过一系列低层次的设计转换,也就是重构,来应用模式,改进设计。
本书目的
撰写本书是为了帮助读者:
理解如何结合重构和模式;
用模式导向的重构(pattern-directed refactoring)改善既有代码的设计;
找出需要进行模式导向重构的代码段;
了解为什么使用模式来改善既有的设计要优于在新的设计早期使用模式。
为了实现这些目的,本书包含以下特色:
一个含有27种重构方式的目录;
示例以实战代码为基础,没有纯示意性的玩具代码;
模式的描述,包括实际的模式示例;
一组坏味 (也就是问题),表示需要进行模式导向的重构;
实现同一模式的不同方式的示例;
就什么时候应该通过重构实现模式、趋向模式以及去除模式给出建议。
为了帮助个人和小组学习本书中的27种重构,本书给出了学习顺序的建议。
读者对象
本书的读者是从事或者有兴趣改善既有代码设计的面向对象程序员。他们中很多人都在使用模式和重构,但是从来没有通过重构来实现模式。还有一些程序员对重构和模式知之甚少,但愿意了解更多相关内容。
本书对新项目开发(从头编写新的系统或者特性)和遗留开发(主要是维护遗留系统)都适用。
所需背景
本书要求读者熟悉紧耦合、松耦合等设计方面的概念,以及继承、多态、封装、组合、接口、抽象类和具体类、抽象方法和静态方法等面向对象方面的概念。
书中示例使用Java代码。我发现对于大多数面向对象程序员来说,Java代码都很容易读懂。我有意识地不使用那些Java独有的特性,因此无论你习惯于用C++、C#、Visual Basic .NET、Python、Ruby、Smalltalk,还是其他面向对象语言编程,都应该能够理解本书中的代码。
本书与Martin Fowler的经典著作《重构》[F]息息相关。该书中包含了对许多低层次的重构,例如:
提炼方法(Extract Method)
提炼接口(Extract Interface)
提炼超类(Extract Superclass)
提炼子类(Extract Subclass)
上移方法(Pull Up Method)
搬移方法(Move Method)
重命名方法(Rename Method)
《重构》一书中还有一些更复杂的重构,例如:
用委托替换继承(Replace Inheritance with Delegation)
用多态替换条件语句(Replace Conditional with Polymorphism)
用子类替换类型代码(Replace Type Code with Subclasses)
为理解本书中介绍的模式导向的重构,读者无需了解上面列出的所有重构,相反可以跟随阐释这些重构的示例代码进行学习。但是,如果要获取阅读本书的最佳效果,我推荐你同时有一本《重构》在手。该书是无价的重构资源,而且对理解本书很有帮助。
我要讨论的模式来自经典图书《设计模式》[DP],还有其他作者的作品,包括Kent Beck、Bobby Woolf和我本人的作品。我和同事们在实际项目中都实践了重构实现、重构趋向和重构去除这些模式。通过学习模式导向重构的艺术,你将理解如何重构实现、重构趋向和重构去除本书中没有提到的模式。
阅读本书不必事先成为这些模式的专家,但是对模式有所了解当然会有帮助。为了帮助读者理解所讨论的模式,本书包含了一些简洁的模式总结、模式的UML略图和许多示例实现代码。要更详细地理解模式,我推荐你在学习本书的同时,也结合研读所引用的模式文献。
本书使用UML 2.0表示法。如果对UML不太熟悉的话,不要担心。我也只是知其大略而已。编写本书时,Fowler的《UML 精粹》[Fowler, UD] 一书常伴我左右,不时查阅。
如何使用本书
要概略地了解本书中的重构,可以从学习每个重构的总结(参见5.1节),以及每个重构中“动机”一节的“优点和缺点”开始。
要更深入地理解重构,应该研究每个重构的各个部分,但“做法”一节除外。“做法”一节比较特殊。它的目的是通过建议应该遵循哪些低层次重构,帮助读者实现该重构。理解本书中的重构,并不需要阅读这一节。这一节更可能用作在实际重构时的参考。
本书和《重构》[F] 所讨论的代码坏味(code smell),是识别设计问题和找到有助于解决问题的相关重构的一种有益方式。也可以查看本书和《重构》中的重构列表(按字母顺序排列),找到能够改进设计的重构。
本书记载的是使设计实现、趋向和去除模式的重构。为了帮助你找到着手的方向,3.4节专门讲述这一主题。本书还有一个表列出了所有模式的名称和可以用于使设计实现、趋向和去除模式的重构。
本书历史
我从1999年开始动笔撰写本书。当时,有好几个因素都促使我为模式、重构和极限编程(extreme programming,XP)[Beck, XP]写点什么。首先,我非常吃惊地发现,XP文献中还没有提及模式。我因此撰写了一篇名为Patterns & XP(模式与XP)的论文[Kerievsky, PXP],在该文中我公开地讨论了这一问题,并就如何将软件开发界的这两大主题结合起来提出了一些建议。
其次,我知道Martin Fowler在《重构》 [F] 一书中只写到了几个“通过重构实现模式”,而且他明确表示,希望有人在此方面进一步写作。这看上去是一个很值得努力的目标。
最后,在我和同事教授的设计模式研讨班上,我注意到有些学员需要更多指导,才能决定何时应该在设计中实际地应用模式。知道模式是什么是一回事,而真正理解什么时候去如何应用模式,就完全是另一回事了。我认为这些学员需要学习一些实际的案例,在这些案例中,在设计时应用模式能看到实实在在的效果,因此我开始将这种案例汇编成一个提纲。
当我开始撰写本书时,我遵循了Bruce Eckel 的优秀写作传统,将草稿在网上公开,听取人们的意见。网络真是一个好东西。许多人向我发来反馈,有建议,有鼓励,也有感谢。
随着书稿和想法的不断成熟,我开始在许多会议、讲座和Industrial Logic公司的“模式与重构”强化研讨班上讲授“通过重构实现模式”的主题。这使我获得了更多的改进建议,而且更多地了解到程序员理解这一主题需要些什么。
渐渐地,我认识到重构是审视模式的最佳方式,而且模式正是一系列低层次重构所能达到的最佳目标。
很幸运,书成稿之后,得到了许多经验丰富的专业人士的审阅,他们提出了很多改进建议。我在致谢中提供有关他们的更多情况。
站在巨人肩上
1995年的夏天,我走进书店,第一次见到了《设计模式》[DP]一书,并从此与模式结下不解之缘。我希望感谢四位作者Erich Gamma、Richard Helm(我还未曾谋面)、Ralph Johnson和John Vlissides编写了如此优秀的技术图书。他们在书中所表现出的睿智,使我大大提高了自己的软件设计水平。
大约在1996年,我在一次模式会议上遇到了 Martin Fowler,那时他还没有出名。这就是我们长期友谊的开始。如果Fowler(以及他的合作者Kent Beck、William Opdyke、John Brant和Don Roberts)没有写经典著作《重构》 [F]的话,我真地怀疑自己是否还能写出这本书。与《设计模式》一样,《重构》完全改变了我从事软件设计的方式。
我能够完成本书,全拜《设计模式》和《重构》的作者们的辛勤劳动所赐。对此我感激不尽。
致谢
我是如此幸运,有一位妻子在我写作本书期间全心全意地支持我。Tracy,你是最棒的。我愿与你白头偕老。
我们的两个女儿Sasha和Sophia,都是在我写作本书期间出生的。我要感谢她们在爸爸写作时候表现出的耐心。
在20世纪70年代,我的父亲Bruce Kerievsky将我和哥哥带到工作场所,让我们画那些位于空调房间中的巨大计算机。他还给我们看长长的绿色和白色的计算机清单,上面用巨大的字母写着我们的名字。这些都激励我进入了这个伟大的行业——谢谢你,父亲。
感谢家人之后,应该是技术方面的致谢了。
John Brant 对本书居功至伟。他和他的同事 Don Roberts 都位居世界上最渊博的重构专家之列。John审阅了本书手稿的四个版本,提出了很多想法,并鼓励我删去许多比较平淡的内容。他的真知灼见遍及目录中几乎所有重构“做法”部分的字里行间。Don虽然忙于其他的项目,未能投入更多精力,但是他复查了John的反馈意见,非常感谢。我还要感谢两位为本书题跋。
Martin Fowler 在审阅和建议上用力甚勤,包括简化略图和澄清某些技术讨论。他帮助我改正了一些有问题的 UML 图,而且进行了更新以反映 UML 2.0的变化。我很荣幸Martin选中本书作为他主编的签名系列之一,感谢他为本书作序。
Sven Gorts 下载了本书手稿的多个版本
无封面