原来看到过刘晓伟翻译的第一篇的部分,没想到他把这个系列都翻译完了。翻译的连接是http://blog.csdn.net/lxwde/archive/2005/05/28/382819.aspx。
对比了一下他的翻译,觉得还是把我们在WIKIPRO的翻译放上来对照一下。这篇文章在WIKIPRO目前的译者包括supertclyh,tchaikov和我(Wilddog).
Erich Gamma,作为最畅销书籍《设计模式:可重用面向对象软件基础》 (Addison-Wesley, 1995)的协同作者于1995年登上软件世界的舞台,这部里程碑的著作,常常被称为“四人组之书”,书中列举了23种用于解决设计中常见问题的方法。在 1998年,他与Kent Beck组队开发了JUnit,这是目前在Java社区的单元测试工具中的事实标准。Gamma目前是IBM对象技术国际实验室(OTI)的杰出工程师, 该实验室位于瑞士的苏黎世。他领导着Eclipse社区,并负责Eclipse平台上Java技术的发展。
在2004年10月27日,Bill Venners在加拿大温哥华召开的OOPSLA会议上遇见了Erich Gamma。在这次访谈中,Gamma对软件设计的深入见解被分成多个部分,发表在 Leading-Edge Java on Artima Developer 上。在第一部分中,Gamma描述到用他的方法以合适的方式去思考和使用设计模式,并且描述了模式库,如GoF,与亚历山大语言模式之间的不同。
设计模式的真正价值
Bill Venners:Bruce Eckel和我一起教程序设计的课程,我们已经发现人们迫切地想了解 GoF 的各种设计模式。模式还让相关讲座课程的更受欢迎。目前,在外面,设计模式非常火爆。
Erich Gamma:都10年了,还是这样吗?
Bill Venners:仍然如此,人们想要了解模式,并且我之所以对此深信不疑,是因为“模式”这个词仍然很流行。我希望拨开天花乱坠的宣传,了解你对于下列的 问题的真知灼见:人们应该如何看待模式。他们对于模式的态度应当是什么?人们应该怎样利用模式更好地工作?什么是真正的价值?
Erich Gamma:我认为模式作为一个整体将会帮助人们认识面向对象的思考方式:例如你是怎么利用多态,如何设计对象以方便组合(composition),委 托(delegation),如何平衡责任,以及如何提供可插入的行为。模式不仅仅是通过 shape class 的类层次和多态的 draw 方法来为作图例程提供对象。只有当你已经明白了这些模式之后,才能真正理解多态性。所以模式在总体上对于学习面向对象和设计是有帮助的。
在那之上,每个模式通过不同的特点在你们需要更多灵活性或者需要简练表达一个抽象概念的地方给于帮助,或帮助你精简你的代码。这在大型系 统中是相当大的问题。如何保存层次?如何避免循环依赖?GoF模式将会以简单的工具帮助你解决这些问题。对您的帮助不是通过草率的问题解决方案而是通过解 释如何达到一个平衡。即使在实际使用中该模式是相当抽象的,他们也会提供你有价值是方案实现提示。从我的观点来看模式之所以这么有价值是因为他是可实现 的。
模式的思想是从专家的经验中提炼出来的,它将使你重复别人已经成功的设计。通过这样的做法,你就如同站在专家的肩膀上,并且没有必要重新 去创造整个体系。然而,因为模式使得许多实现富于变化,所以你必须保持大脑清醒。最终,当模式已经向你提供设计模块的名称时,它将继续向你一部字典用于描 述和讨论一个特别的设计。
另外一个问题就是我们如何教授模式的思想。我并不知道你要怎么做,但我认为你不能简单的把教授当作一门课然后列举23种模式思想。这种方法将不会带来任何东西。你必须感觉到一个有许多问题的设计所持有的痛苦。我猜想一旦你已经感觉这个设计痛苦后你就会感谢这种模式思想
Bill Venners: 什么痛苦?
Erich Gamma: 例如你认识到自己的设计不够灵活,一个简单的改变搅乱了整个系统,你不得不再写两倍的代码,或者代码变多且更加复杂。如果你那时在如此糟糕的形势下运用一 个模式,那么痛苦就将消失并且之后你将感觉很舒服。睁开眼睛去认识它,事实上这种模式,策略,可以解决我的问题。并且我认为那是我真正喜欢的有意思的教学 方式。
当我最初开始教授时,那是相当的无聊,因为我那时只是把模式逐个列出来。我发现如果用真实的例子去激发学生如何运用模式,那将变的更加有趣。换句话说,你必须在真实的案例中提出问题—人为设置的题目不具备这些东西。在OOPSLA我收到一本名为《Heads First Design Patterns》的书。这是一本好书,并不仅仅是因为这本书读起来很有趣,而且这本书的作者们通过新颖的,栩栩如生的方式来教授设计模式的精髓。
Bill Venners: 在现实世界中,当我觉得某个地方特别不对劲时,就能用一种现成的解决方案搞定它。那么这就是模式的价值吗?
这正是我建议大家使用模式的方式。不要一开始就将模式运用到设计中去,当你明白更多问题的时候再使用它。正因为如此,我喜欢在事后使用模 式,重构程序,让模式显现出来。在模式刚开始流行时,我在一个新闻组中看到一个帖子,有人声称在一个程序里他们尝试用上全部23种GoF模式。但他们说他 们失败了,他们只用到了其中的20种。程序员们希望客户能够再叫他们返工一次,这样说不定他们能把另外3种弄进去。
尝试用上所有的模式是行不通的,这样你最终的设计将是一种矫揉造作的设计—即臆测出来的设计方案将拥有没人想要的灵活性。这些年的软件太 复杂了。我们不能猜想它的其他功能,我们必须侧重于它需要什么。那就是为什么我喜欢重构模式,人们要学习到当他们面临某个问题或代码难题时,他们能够从他 们的模式工具箱中找到一个解决方案。
Bill Venners: 那太有意思了,因为我的第二个问题就是我已经观察到人们经常觉得在设计中用的模式越多就越好。在我的设计研讨会上,我让参与者们做设计,最终他们将向其他人展示他们的设计。几乎完全不会改变的是,展示者往往只是展示他们的设计中运用了多少种模式,即使我告诉他们目标仅仅是一个简单的,容易理解的API程 序,而不是为了赢得一场 I-used-the-most-patterns(我使用了最多模式)的比赛。我刚刚听到您提起过该问题,那不是正确看待模式的方式。那么如果不能这样 看待,怎样才能给在设计中使用模式一个合适的判断呢。
Erich Gamma: 许多模式是关于其扩展性和复用性的。当你真的需要他的扩展性时,那么这些模式将会向你提供一种思路,那将是很酷的。但是当你不需要它时,你应该使你的设计 简单并且不要增加没有必要的间接等级。在我们 Eclipse的座右铭中有一条是在我们需要扩展性的地方我们才使用它。事实上,如果你对我们在Eclipse中如何使用模式感兴趣,我曾专门写了一个章 节来试图表达这些模式在ECLIPSE中的用法。在这个章节中,我使用设计模式去解释部分Eclipse架构。
Bill Venners: 就扩展性而言,您的意思是?
Erich Gamma: 那就是说你不改变当前代码就可以改变程序的行为--经典的00主题之一。你可以重用一些已被特别的问题采用的东西
Bill Venners: 你原来和 Kent Beck 写过一篇文章叫"JUnit:A Cook's Tour"[见资源],你和读者一起回顾了JUNIT的设计,你在里面提到“从一无所有开始,不断地一个接一个的使用模式, 直到你完成了整个系统架构”我想这个方法也许是受到了克力斯多夫.亚历山大的启发。他也专注于模式在架构中的应用。你认为一层一层叠加模式的方法是行之有 效的设计方法吗?
Erich Gamma:整个过程从某种意义上来说是一种合成。我们确实重新构建了之前对JUNIT的设计,但我们并没有采用模式驱动的方法开发 JUnit。我们用的是一种严格的测试驱动的方法。在JUnit里,真正核心的是关于测试的核心抽象,和围绕这个核心抽象的一些其他设计要点的融合,也就 是被充实了的模式实例。你可以经常在成熟的设计中看到这些东西。通常有一些关键的抽象会作为整个设计的中心,围绕这些抽象你可以完成不同的事情。因此你看 到很多模式是从一个象那样的中心中发展出来的。但我并不把它作为评价质量的标准。
Bill Venners:这是不是你曾提到的“模式密度?”
Erich Gamma:对,完全正确,模式不断在核心抽象旁边衍生出来。
Bill Venners:你说过TestCase是JUnit的核心抽象。
Erich Gamma:事实上,它是一个Test 接口的实现,不过我们确实是从TestCase开始,并从那里扩展的。
Bill Venners:那么,你怎么定义密度?是围绕核心抽象的模式数量么?你刚才提到JUnit的设计过程是一种合成。
Erich Gamma:(有待确认)我说的合成是指,当我们在使用测试驱动的开发过程中,除开所有测试活动后剩下的那部分。这是一个非常笼统的说法。密度表现了围绕测试所编码的模式。
当初,我们在设计JUnit 的时候并没无意把模式都塞进去。我们用的是测试驱动的方法,首先写一个我们希望通过的测试,一旦这个测试通过,我们再回头看我们可以怎么来优化代码。用测试驱动的方法来开发一个测试框架不是一点挑战都没有,但当你完成了基础工作后,它会非常之顺利。你知道,我和Kent在设计JUNIT时对模式都非常熟 悉,因此很自然地,我们会说“嘿,这是一个 composite。”组合是JUNIT中使用的一种模式。我们也使用template method。这是一个基本的模式。我们也使用 command 模式,当然这是一个关键的模式。我们从测试出发,“哦,这是一个 command,哦,这是一个template”。因为我们对模式都很熟练,我们的交流非常快捷,因此设计速度非常快。
这事实上很好地说明了模式为我们提供了多么好的设计词汇。同理,当你看UML图时,你看到框框和箭头,但他们不会真正告诉你在这些关系下 隐藏的意思。但你一旦理解了模式,他就会解释这些关系是关于什么的。如果是一个观察者(observer)模式,那么在两个类中间为什么会有连线的原因非常清楚。就像一个人在观察另一个人。你很准确地能理解什么在发生。我想,这就是关键。模式给了我们一种语言来交流设计。事实上,JUnit 的开发还没有结束,Kent 和我正在开发 JUnit 4。我们正在一直在用测试驱动的方法改进 JUnit。我们有一个主旨,就是降低入门的门坎。为了做到这一点,我们正在借助一些 J2SE 5 的特性 (如 annotation),来让 JUnit 更好用。
Bill Venners: 什么是亚历山大所说的模式语言?
Erich Gamma: 亚历山大有一个雄心勃勃的目标,要通过建立架构来提高生活质量。为了达到这个目标,亚历山大开发了模式语言。模式语言由一系列互相依赖的模式组成,模式语言引导设计者从相互独立的模式到使用模式贯穿到整个设计。当我们开始设计模式时,我们没有这么大的野心,我们更多的是采用基于微观架构的自底而上的方法。
Bill Venners:你说的“自底而上”是什么意思?
Erich Gamma:让我们回顾一下,我怎是么进入模式世界。我想这可以回答你的问题。我曾和Andre Weinand一起在ET++项目,这是一个全面的C++类库框架。我从ET++中学到,一个成熟的框架总是明显地包含了很多重复出现的设计模式,可以让 你得到更多的东西,像扩展性,解耦性,和最终的优雅性。这种结构可以被考虑为一个作为用来充实整个系统架构的微架构。我用了大约1打的微架构来结束我的论文。模式语言和这种方法比较,是自上到下而衍生出的一系列相互交织的模式,而微架构更多的是采用独立的模式,自底而上,相互关联。模式语言可以让你贯穿整 个设计,然而,我们也可以使用这些小的结构,基于一点一点的工程知识。我承认这个方法并不是雄心勃勃,但仍然非常重要和有用。
Bill Venners:模式语言是不是像一门上下文无关的语法,你可以用来编制相同类型的程序?
Erich Gamma:从一定的抽象层面上说上有一些相似的地方。和语法定义一组程序一样,模式设计语言可以定义一组解决方案。克里斯托夫.亚历山大说,他的方法表述一个解决方案,可以多次应用而绝不雷同。但我对此的意见是,这正是我们的方法和亚历山大不同的地方。
Bill Venners:他是什么意思?如果我有一个上下文无关的语法,它并不能自动产生程序,我还是得写程序。
Erich Gamma:你仍然需要做决策,但模式语言给了你更多的指导,它有一些流程。比如说你要设计一个你感觉舒服的房间,他会说,首先要在两面墙上打上灯 光。好,你现在搞定了灯光,下一步该干什么?你怎么摆放你的窗户?会有一些其他模式来描述这个问题的解决方案。他会引导你来打穿墙壁。这种关连正是模式语言和我们在“四巨头”的书中列出的模式库之间的差别。在这点上,我们发现我们的微架构也是没有立足之地的。他们相互关联。我们把它们的关联画在了这本书的封面上。亚历山大的忠诚拥趸认为这是我们书中唯一有价值的地方。
Bill Venners: 听上去,这更像是设计的方法论。你采用此方法,依次做完1、2、3,最后你自然会得到一个美观舒服的房间。
Erich Gamma:正确,当你采用亚历山大模式按照一定顺序采用模式时,就是这个样子。而我们并没有严密规定一个特定的顺序。当你有问题时,我们有一个解决方案,但我们并不会强调下一步该干什么。我们不会给你下一步的提示。亚历山大方法在这一点上要细致得多。JUNIT使用了一点模式语言的方法,因为它能帮 你写一个测试用例。在JUNIT的文档中,KENT和我用了一个迷你模式语言来说明怎么执行一个测试,比如说你先从一个测试开始,然后提取通用设置代码, 然后开始完成一组测试等等。
【免责声明:本文翻译仅为外语学习目的,原文作者个人观点与译者及译言网无关】