大多数关于设计模式的书都是基于C++和Java的。而Ruby是一门十分特别的语言,Ruby的特性使设计模式的实现和应用都变得更加简单。在本书中,Russ Olsen演示了如何将Ruby语言的强大和优雅与设计模式相融合,从而用更少的代码编写出更完善和高效的软件。
在纵览了设计模式的历史、概念和意义之后,作者给出了Ruby语言的快速入门,使不同经验程度的软件开发者都能立刻开始在Ruby中运用设计模式。本书着重介绍可以简化设计模式使用的Ruby语言特性,比如动态类型、代码闭包和混入法等,这些特性大大提高了代码的可复用性。
本书从Ruby的角度阐释了“四人组”所提出的设计模式中的14个,分别介绍了这些设计模式所解决的问题,讨论这些模式的经典实现方法在Ruby环境中是否理想,并介绍针对Ruby进行的优化。很多设计模式在Ruby中通过一两行简单的代码即可实现,而无需编写像在其他语言中所必需的繁琐的模板代码。
本书总结了Ruby社区中出现的新模式并定义了创造性的新设计模式。这些新模式包括使用元编程来创建自定义对象、基于Rails、强大的“惯例优于配置”模式,帮助整合整个程序和框架等。
本书具有实用的特质,帮助你构建更完美的软件,愉悦你的Ruby编程体验,获得更多的回报。
无
我曾经共事过的一个同事一直对我说,那些厚重的,关于设计模式的书足以证明编程语言的匮乏。他的意思是,因为设计模式是代码中的约定惯例,所以一个好的编程语言应当全面地整合这些设计模式,使它们消失在代码中。
举一个极端的例子,在20世纪80年代,我曾参与的一个项目是用C语言编写面向对象代码。是的,是C语言,而不是C++。我们所采用的技巧是将每个“对象”映射到一个函数指针列表。然后通过查找表中的指针来调用相应函数从而操作我们的“对象”,从而模拟对于对象中方法的调用。这种方法比较笨拙而且烦琐,但是能够解决问题。如果对这个方法进行归纳总结,可能会称其为“面向对象”设计模式。当然,后来有了先进的C++,以及后来的Java,我们的面向对象模式便消失了。今天,我们不太会将面向对象看作一种设计模式——因为今天的它实在太简单。
但很多情况仍未变得简单。名副其实的“四人组”之书(《Design Patterns: Elements of Reusable ObjectOriented Software》, Gamma, Helm, Johnson和 Vlissides著)依旧是每个程序员的必修读物。然而对于该书所说的许多模型,在今天各类流行语言(Java和C++,和(或)C#)中的具体实现看上去多少有点像我那个20世纪80年代的过时手工对象系统。它太痛苦、太冗长、太容易出错。
Ruby编程语言带着我们向我那位同事的理想迈进了一步。用Ruby实现设计模式是如此简单,以致有时候设计模式淡出到程序背后。由于以下原因,用Ruby构建模式变得更简单:
Ruby是一种动态类型语言。免去了静态类型,Ruby极大地减少了大多数程序的代码量,包括用来实现设计模式的代码。
Ruby内建代码闭包。闭包允许我们传递一段代码并指定其执行访问而不必辛苦地构建空而无用的整个类和对象。
Ruby的类是真实的对象。因为类在Ruby中即另一个对象,我们可以像对待任何其他对象一样对Ruby类进行常规的运行时操作:我们可以创建全新的类。我们可以通过增加或删除方法来修改已存在的类。我们甚至可以克隆一个类,修改它的副本,而保持原类不变。
Ruby具备一个优雅的代码重用系统。除了支持普通的类继承以外,Ruby还允许我们定义混合(mixin)。那是一种简单但灵活的方法,使代码可以被若干个类共享。
以上这些因素使得Ruby代码变得可压缩。在Ruby中,像在Java和C++中一样可以实现复杂的想法。不过只有通过Ruby才可能把实现的具体细节更有效地隐藏起来。正如你将在以后见到的那样,许多设计模式在传统静态语言中需要大量的模板代码,而在Ruby中只需要一两行即可。你可以简单地使用include Singleton命令将类变成一个单例(singleton)。你可以像实现继承那样简单地实现委托(delegate)。因为Ruby使每行代码能做更多有趣的事情,最后,只需要更少的代码来完成工作。
这并不是简单地在键盘上偷懒,而是对DRY(不重复你自己)原则的应用 。我不认为现在还会有人对旧C语言中的面向对象模式的消亡而感到惋惜。它的确曾为我解决了问题,但我也不得不花时间为它工作。Ruby提供了一个通向更高境界的阶梯,只需要工作一次,便可以将模式从代码中压缩出来。简而言之,Ruby使你把注意力放在解决实际问题上而不是其他工作中上。我希望本书能够帮助你了解如何达到那个境界。
本书的目标读者
简单地说,本书写给那些想知道如何用Ruby有效地开发软件的人。假设你熟悉面向对象编程,但对设计模式没有任何了解,你可以在阅读本书的过程中学会。
你也不需要掌握很多Ruby知识来阅读本书。你会在第2章中找到对于这门语言的快速入门。同时,我会对每个Ruby语言特定的环节进行详细解释。
本书内容的组织结构
本书分为三个部分。第一部分从整个设计模式发展的历史和背景的最简单纲要开始,涵盖重点的Ruby语言的快速入门。
第二部分是本书的主体,通过Ruby的角度来讲解四人组提供的设计模式。这个模式要解决怎样的问题?这个模式的传统实现方法(四人组给出的方法)在Ruby中是怎样的?传统实现方法在Ruby中是否有效?Ruby是否提供了其他选择让实现变得更简单?
第三部分将讲述随着Ruby语言的推广和发展而出现的3种新设计模式。
有言在先
在重复那句我多年来一直默念的箴言之前,我无法在一本关于设计模式的书上签下我的名字:设计模式是一小盒封装好的用来解决常见编程问题的方案。在理想的情况下,当遇到一个相应的问题时,你应当激活对应的设计模式,然后就会解决问题。但第一步(等待相应问题的到来)经常困扰一些工程师。只有当你面对应当使用设计模式来解决的问题之后,才能说你正确地应用了设计模式。
在一些圈子中,对于设计模式的滥用已经玷污了设计模式的名声。我可能会争辩,用Ruby能比用其他语言更简单地写一个使用工厂方法的转换器,然后用它获得一个生成器的代理器。那个生成器随后创建一个命令去进行一个2加2的操作。Ruby的确能让这些步骤的实现变得简单,即使在Ruby中,这样的设计也没有任何意义。
你也不能将程序的构建看作一个对于现有设计模式简单拼接的组合。任何有趣的程序都有特殊之处,一些只用来完美地解决特定问题的代码。设计模式是要帮助你认识和解决在软件创建过程中重复产生的一般问题。使用设计模式的优势在于,让你能够迅速克服一些别人已经面对过的问题,从而使你能调整难点——那些只有在你的程序中面对的问题。设计模式不是万能的灵丹妙药,无法帮你解决所有的设计问题。它们仅是一个技巧,一个帮助你构造程序的非常有用的技巧。
关于本书中的代码风格
用Ruby编程变得如此有趣的原因之一是,这门语言尽量不影响你进行程序设计——如果有多种方法可以用来描述事物的话,Ruby通常支持所有这些方法:
出于语法上的考虑,Ruby也尽量不强调语法。只要表意清晰,Ruby尽可能地让你省略不必要的东西。比如,在调用一个方法的时候,你可以省略参数列表两旁的括号:
当你定义一个函数的参数列表时,以及编写if语句的条件时,你甚至都可以省略括号。
所有这些快捷方式能够在编写真正的Ruby程序时带来方便。然而,当它们被大量使用的时候,通常会给初学者带来困惑。所以许多刚用Ruby的程序员可能对以下格式感到难以适应:
或者
也可能
由于本书主要讨论Ruby的深层力量和优雅,而不是纠缠语言的语法细节上,所以,我尽量保持平衡,一方面尽量让示例代码看上去像真正的Ruby代码,另一方面,确保它们对初学者来说是友善的。在具体的实践中,我采用了一些显而易见的快捷方式,同时避免使用更极端的窍门。这并非意味我不了解,或不赞同Ruby的语法快捷功能。我只是更想对使用Ruby的新手们尽量保持概念的优雅。当你忘我地投入这门语言之后,你会有大量的时间学习语法快捷功能。
大多数关于设计模式的书都是基于C++和Java的。而Ruby是一门十分特别的语言,Ruby的特性使设计模式的实现和应用都变得更加简单。在本书中,Russ Olsen演示了如何将Ruby语言的强大和优雅与设计模式相融合,从而用更少的代码编写出更完善和高效的软件。 在纵览了设计模式的历史、概念和意义之后,作者给出了Ruby语言的快速入门,使不同经验程度的软件开发者都能立刻开始在Ruby中运用设计模式。本书着重介绍可以简化设计模式使用的Ruby语言特性,比如动态类型、代码闭包和混入法等,这些特性大大提高了代码的可复用性。 本书从Ruby的角度阐释了“四人组”所提出的设计模式中的14个,分别介绍了这些设计模式所解决的问题,讨论这些模式的经典实现方法在Ruby环境中是否理想,并介绍针对Ruby进行的优化。很多设计模式在Ruby中通过一两行简单的代码即可实现,而无需编写像在其他语言中所必需的繁琐的模板代码。 本书总结了Ruby社区中出现的新模式并定义了创造性的新设计模式。这些新模式包括使用元编程来创建自定义对象、基于Rails、强大的“惯例优于配置”模式,帮助整合整个程序和框架等。 本书具有实用的特质,帮助你构建更完美的软件,愉悦你的Ruby编程体验,获得更多的回报。
《Design Patterns: Elements of Reusable ObjectOriented Software》的作者被读者亲切地称为“四人组(GoF)”。该书是第一本作为设计模式参考的主流书籍。从1995年至今,该书已经售出了50多万册。毫无疑问,它影响了全球数以百万计的程序员的思路和代码。我仍然清楚地记得在20世纪90年代末我第一次买那本书时的情景。部分热情源自向我推荐该书的同辈人。我将它视为我迈向一个成熟程序员的一步。我在几天内便翻遍了那本书,并急切地构想着每一个模式的实际应用。
大家普遍认为设计模式的最大用处在于,当程序员们进行关于开发的讨论时,为他们提供一个能够清楚描绘设计决定的词汇库。特别是在结对编程(极限编程和其他敏捷开发的基础)的情况下,设计是一个进行态的共享步骤。你能够轻松地跟与你结对的同事说:“我觉得需要在这里使用些策略”、或者“让我们给这个功能加一个观察器。”
在一些公司里,考察对于设计模式知识的把握程度已经成为一种快速检阅程序员应聘者的途径。在那里通常会听到:
“你最喜欢的设计模式是什么?”
“嗯……工厂模式吧?”
“谢谢你前来面试,门在那里。”
上面说到的“最喜欢”的模式是不是听起来有点奇怪?我们钟爱的设计模式应当是对于给定的情况能对症下药的那个。缺乏经验的程序员在学习设计模式时容易犯的一个典型错误是,把一种模式当作目标去实现,而不是当作一种手段。为什么会有人为了好玩而去实现设计模式时又找不着头绪?
至少在静态类型的世界里,实现设计模式需要解决一些技术难点。最好的情况是,你使用一些忍者技巧显示你超群的编程能力。而在最糟糕的情况下,你最后得到的是一堆从模板文件里七拼八凑而成的废物。所以,设计模式至少对于像我这样的奇客(Geek)来说是一个有趣的题目。
那么,用Ruby实现四人组所提出的设计模式困难吗?不一定。对于入门者来说,没有了静态类型的Ruby大大减少了实现程序的代码总量。Ruby标准库也以单行包含的方式提供一些最常见的模式。而另外的一些也构建在Ruby语言自身中。比如,四人组所说的Command对象本质上就是对一段用来做特殊事情的代码的包装,即在某个时刻运行一段特定的代码。当然,这是对Ruby中的block对象(或Proc)的一个相当准确的描述。
Russ自2002年起使用Ruby进行工作。他知道最有经验的Ruby用户早就通晓设计模式,并且知道如何运用。所以,他在本书中遇到的最大挑战,就我所知,是要以一个既能和专业Ruby程序员相关相通,又能帮助初学者走近我们所热爱的这门语言的角度来撰写此书。我认为他成功了,你也会这样认为。再用Command对象举例子:它最基本的实现是简单地采用一个block。当加入了状态和一些行为后,实现就变得一点都不简单了。Russ在此为我们提供了专用于Ruby的、被证明过的建议,而且“药到病除”。
本书的另一个优点就是,加入了Russ定义的专用于Ruby的新设计模式。Russ对它们进行了详细的说明,其中包括我最喜欢的内部域指定语言。就像一个Interpreter(解释器)模型的进化,我相信他对这个主题的论述,使本书出版界在本领域中的第一部有益的著作。
最后,我觉得本书会给刚开始在专业工作中使用Ruby的人和来自其他并不十分强调面向对象设计和模式的语言(比如PHP)背景的人带来巨大的福音。在描述这些设计模式的过程中,Russ捕捉了我们用来解决每天使用Ruby编程时都会遇到的障碍的精要——对于新手来说,这可谓是无价之宝。本书具有如此多的优点,我早就将它列入送给我的新同事和朋友的礼物清单中。
——Obie Fernandez专业Ruby丛书编辑
Russ Olsen:Russ Olsen: 从事软件开发长达25年。多年来,他所带领的项目经历了几代计算机编程技术的革新:从FORTRAN到C、C++,再到Java。他自2002年开始使用Ruby。他目前领导了一个Ruby的研究小组并撰写一个人气极旺的博客Technology As If People Mattered(www.russolsen.com)。
谈熠 陈熙:暂无简介
随着计算机程序设计语言的不断发展和进步,动态语言已经得到开发领域的认可,并在软件行业的各个领域中获得长足的发展。今天,Ruby已经成为世界上发展最快的程序设计语言之一。一个充满热情和创造力的社群围绕Ruby,开展着各种激动人心的工作。这个社群无需豪言壮语,所有的工作都在扎扎实实地推进,人们被自己内心的力量驱动着,而这种力量来自于Ruby语言的强大和优雅。使用这门语言也是莫大的乐趣。
自1994年,四人组(GoF)的名著《Design Patterns: Elements of Reusable ObjectOriented Software》问世以来,设计模式便成为软件工业的圭臬。四人组所提出的设计模式总结归纳了传统软件开发的经验,为开发中所遇到的各种常见问题提供了解决之道。Ruby语言的动态特征恰恰为这些设计模式的实现提供了一个轻盈而高效的平台。此外,Ruby本身具有传统的静态类型语言所不具备的动态优越性,这些高级特性为Ruby语言创造了域指定语言、元编程和惯例优于配置等设计模式。传统的软件开发思路是:好的设计会产生好的软件。因此在实际开发之前,值得花时间做一个全面而细致的设计。而在阅读本书之后,你会发现Ruby使你的设计灵活地贯穿于开发之中。
此书由机械工业出版社出版。——编辑注本书由谈熠和陈熙合力翻译,在翻译中得到了陈理人、陈慧勤、陈少科和金爱珍等朋友的指导和帮助。借此机会,特别感谢机械工业出版社华章分社引进此书,并将如此重要的一部书交托给我们来翻译,希望译文能不辱使命。我们还要感谢华章的编辑不辞辛劳的工作。
Ruby和基于Ruby的著名程序框架Rails在国内的应用开始步入快速发展阶段。我们虽然有数年的使用Ruby的工作经验,然而Ruby和Rails社区中如泉水般喷涌的新技术始终鞭策着我们不断地学习和埋头奋进。限于译者水平,译稿中若存有这样那样的错误,恳请你不吝指正。在Ruby on Rails中文网站的用户社区http://rubyonrailscnorg/community/中,有不少国内使用Ruby和Rails的顶尖高手。如果你遇到了技术方面的问题,你可以在那里最快地找到解决之道。此外,也可以通过电子邮件联系我们:yi@rubyonrailscnorg 。
译者
2008年8月
本书的赞誉
译者序
序
前言
致谢
第一部分设计模式和Ruby
第1章使用设计模式创建更好的
程序2
11四人组2
12模式的模式3
121把变和不变的事物分开3
122针对接口编程而不对实现编程3
123组合优先于继承5
124委托、委托、委托8
125你不会用到它9
1323种模式中的14种10
14Ruby中的设计模式12
第2章从Ruby起步13
21交互式Ruby13
22说hello world14
23变量15
24Fixnums和Bignums17
25浮点数18
26这里没有原始类型18
27但是有时没有对象19
28true、false和nil19
29判定、判定21
210循环22
211更多关于字符串24
212符号27
213数组27
214散列29
215正则表达式29
216自己的类30
217获取一个实例变量31
218对象问:我是谁33
219继承、子类和超类34
220参数选项35
221模组36
222异常38
223线程39
224管理分散的源文件40
225本章回顾41
第二部分Ruby中的模式
第3章使用模板方法变换算法44
31迎接现实中的挑战45
32将不变的部分独立出来46
33探究模板方法模式48
34钩子方法49
35但是类型声明都去哪里了51
36类型、安全和灵活性52
37单元测试并非可有可无53
38使用和滥用模板方法模式55
39模板方法模式的实际应用56
310本章回顾57
第4章使用策略替换算法58
41委托、委托、还是委托58
42在策略和环境中共享数据60
43再说鸭子类型62
44Proc和代码块63
45快速而随性的策略对象66
46使用和滥用策略模式68
47策略模式的实际应用68
48本章回顾69
第5章通过观察器保持协调71
51随时待命71
52更好的随时待命方法73
53提取可被观察能力支持的代码75
54使用代码块作为观察器78
55观察器模式的异体79
56使用和滥用观察器模式80
57观察器模式的实际应用81
58本章回顾83
第6章使用组合模式将各部分组成
整体84
61整体和部分84
62创建组合86
63使用运算符将组合模式打扮整齐89
64给予数组的组合类90
65一种不方便的差异91
66给各层次指明方向91
67使用和滥用组合模式93
68组合模式的实际应用94
69本章回顾96
第7章通过迭代器遍历集合97
71外部迭代器97
72内部迭代器99
73比较内部迭代器和外部迭代器100
74无可比拟的Enumerable101
75使用和滥用迭代器模式103
76迭代器的实际应用104
77本章回顾107
第8章使用命令模式完成任务109
81子类大泛滥109
82一个更简便的方法110
83代码块即命令111
84用于记录操作的命令112
85使用命令取消一个操作115
86命令队列117
87使用和滥用命令模式118
88命令模式的实际应用119
881ActiveRecord数据移植119
882Madeleine119
89本章回顾123
第9章使用适配器填补空隙124
91软件适配器124
92几乎错过127
93适配器的另一种选择128
94修改单个实例129
95适配还是修改131
96使用和滥用适配器模式131
97适配器模式的实际应用132
98本章回顾132
第10章通过代理来到对象面前134
101使用代理进行拯救134
102保护代理136
103远程代理137
104虚拟代理让人变懒138
105取消代理的苦差事140
1051消息传递和方法140
1052method_missing方法141
1053发送消息142
1054无痛的代理142
106使用和滥用代理145
107代理模式的实际应用146
108本章回顾147
第11章使用装饰器改善对象148
111装饰器:丑陋代码的解药148
112正式装饰153
113减轻代理的郁闷154
114实现装饰器模式的另一种动态方法155
1141装饰方法155
1142使用模组进行装饰155
115使用和滥用装饰器模式156
116装饰器的实际应用157
117本章回顾158
第12章使用单例确保仅有一个159
121一个对象,全局访问159
122类变量和类方法159
1221类变量159
1222类方法160
123Ruby单例应用的第一次尝试162
1231管理单个实例163
1232确保只有一个163
124单例模组164
125勤性单例和惰性单例165
126其他单例模式的实现方法165
1261使用全局变量作为单例165
1262使用类作为单例166
1263使用模组作为单例167
127安全带还是拘束衣168
128使用和滥用单例模式169
1281实际上就是全局变量169
1282到底需要多少这样的单例170
1283在需要知道的基础上的单例170
1284减轻测试的郁闷172
129单例模式的实际应用173
1210本章回顾173
第13章使用工厂模式挑选
正确的类174
131一种不同的鸭子类型174
132模板方法再露一手176
133参数化的工厂方法178
134类也是对象181
135坏消息:你的程序搞大了182
136对象创建的组合183
137再论类就是对象185
138协调名字186
139使用和滥用工厂模式187
1310工厂模式的实际应用188
1311本章回顾189
第14章通过生成器简化对象创建190
141制造计算机190
142多态生成器193
143生成器能保证产生健全的对象196
144可重用的生成器196
145使用魔术方法制作更好的生成器197
146使用和滥用生成器模式198
147生成器模式的实际应用198
148本章回顾199
第15章使用解释器组建系统200
151用以完成任务的正确语言200
152构建一个解释器201
153一个文件查找解释器202
1531查找所有文件203
1532根据文件名查找文件203
1533大文件和可写文件204
1534加入Not、And和Or的更复杂的
检索205
154创建AST207
1541一个简单的分析器207
1542没有分析器的解释器209
1543让XML和YAML进行分析
工作210
1544为更复杂的分析器使用Racc211
1545让Ruby作分析211
155使用和滥用解释器模式211
156解释器模式的实际应用212
157本章回顾213
第三部分Ruby的设计模式
第16章采用域指定语言打开系统216
161特定语言的域216
162备份文件的DSL217
163是数据文件,更是程序217
164构建PackRat218
165将DSL合成一体220
166评估PackRat221
167改进PackRat222
168使用和滥用内部DSL224
169内部DSL的实际应用225
1610本章回顾226
第17章使用元编程创建自定义
对象227
171通过方法度身定制的对象和方法227
172通过模块自定义对象和模块229
173召唤出崭新的方法230
174到对象的内部看看233
175使用和滥用元编程234
176元编程的实际应用235
177本章回顾238
第18章惯例优于配置239
181一个优秀的用户界面——对于
开发者240
1811预期需求240
1812让他们说一次240
1813提供一个模板241
182一个消息中转器241
183选择适配器243
184载入类244
185增加一些安全性246
186帮助用户开始使用248
187评估消息中转器249
188使用和滥用惯例优于配置模式250
189惯例优于配置的实际应用250
1810本章回顾250
第19章总结252
附录254