本节书摘来自异步社区《设计模式沉思录》一书中的第1章,第1.1节对模式的十大误解,作者【美】John Vlissides,更多章节内容可以访问云栖社区“异步社区”公众号查看。
第1章 介绍
设计模式沉思录
在阅读本书之前,如果读者还没有听说过一本名叫《设计模式》(Design Patterns: Elements of Reusable Object-Oriented Software [GoF95])的书,那么现在正好可以去找一本来读。如果读者听说过该书,甚或自己还有一本但却从来没有实际研读过,那么现在也正好应该好好研读一下。
如果你仍然在继续往下阅读,那么我会假设你不是上述两种人。这意味着你对模式有大致的了解,特别是对23个设计模式有一定的了解。你至少需要具备这样的条件才能够从本书受益,这是因为它对《设计模式》中的材料进行了扩充、更新和改进。如果不熟悉所谓的GoF模式——也就是刚才提到的那23个设计模式,那么读者将会很难理解书中的见解。事实上,在阅读这本书的时候,最好备一本《设计模式》在身边以便随时查阅。我还要假设你熟悉C++,这么假设应该很合理,因为我们在《设计模式》一书中也做了同样的假设。
现在让我们来实际检验一下,看你是否能用不到25个字来描述COMPOSITE模式的意图。你可以考虑一分钟。
※ ※ ※
在描述COMPOSITE模式的意图时,你是不是句斟字酌?如果确实如此,好,没问题。其实你大可不必把这个小测验看得太严重了,不妨放松一点。如果你知道该模式的意图,但只是无法准确描述出来,那么不必担心——本书同样适合你。
但如果你的头脑中完全是一片空白,那么很不幸,我的开场白显然没有起作用。我建议你放下本书,拿起一本《设计模式》,从第163页①开始阅读,直到读完“实现”那一节。对该书第xv页中列出的其他模式,也采取同样步骤。如此一来,你就可以对背景知识有足够的了解,从而使得本书对你有用。
你可能会想,为什么本书会取名为Pattern Hatching?我最初选择这个名字,是因为计算机科学中有类似的概念。(此外,与模式有关的好书名都已经被用了。)但此后,我逐渐认识到它非常好地表达了我写作的意图。Hatching之意并非创造,而是在现有的基础上进行拓展。用于此处非常贴切:如果把《设计模式》看成一盒鸡蛋,那么许多新生命将会在这里破壳而出②。
请相信,我并不仅仅是效仿《设计模式》。我的目的是在它的基础上进行拓展,运用其中的概念,并使这些概念对读者更加有用。本书介绍了一些技巧,来帮助我们决定在不同的情况下,应该使用哪些模式以及不应该使用哪些模式。本书不仅对我们已有的一些模式提出了新的见解,还可以让读者见证我们开发新模式的整个过程。本书还提供了大量的设计示例,其中一些是久经考验的,另一些是试验性质的,或者说是“半成品”,还有一些则完全是主观推测——很可能是纸上谈兵的设计,根本经不起实践的检验,但它们也可能会蕴含未来健壮设计的种子。
我衷心地希望本书能够加深你对设计的感悟,提高你对模式的认识,并开阔你软件开发的视野。这些都是我在使用模式时曾有过的经历,希望它们也能成为你自己的宝贵经历。
1.1 对模式的十大误解
这些日子,模式引起了大家强烈的兴趣,同时还伴随着一些迷惑、诧异和误解。这在一定程度上体现了主流软件开发人员认为这个领域有多么新,虽然从严格意义上说,它并不是一个新领域。这个领域的快速发展,也造成了一些空白。作为模式的倡导者,我们对此负有一定的责任:我们虽然一直努力让大家理解和接受模式([BMR+96、Coplien96、CS95、GoF95、MRB98和VCK96]),但是工作并不彻底。
为此,我感觉自己有义务来纠正那些对模式比较明显的误解,这些误解我常常耳闻,甚至可以自成模式了。我甚至还开玩笑地采用模式的形式来表述它们……直到那一刻我幡然醒悟:将任何事物都归纳为模式,这种行为本身就是对模式的一种误解!无论如何,请记住我并不是代表模式社区在发言。虽然我认为大多数模式专家都会同意这些是对模式最常见的误解,但就如何消除这些误解而言,他们的意见可能会与我的相左。
这些年人们对模式众说纷纭,令我反复思考,众多误解不过分为三类:一类有关模式是什么,一类有关模式能够做什么,还有一类有关一直以来在推动模式的社区。我所列举的“十大”误解都可以被归到这三类中。因此,我会将它们分门别类。首先来看看关于模式是什么的误解。
误解1:“模式就是在一种场合下对某个问题的一个解决方案。”
这是Christopher Alexander的定义[AIS+77],因此把它算作一种误解可能会显得有些离经叛道。但下面这个反例应该能够显露出它的不足。
问题: 如何在过期之前兑现中的彩票?
场合: 离最后期限只有一小时,一条狗把彩票吃了。
解决方案: 剖开狗的肚子,取出彩票,然后飞奔到最近的兑现点。
虽然这是在一种场合下对一个问题的解决方案,但它并不是一个模式。那它缺少了什么呢?至少需要三样东西。
(1)再现(recurrence),这使得该解决方案不仅与当前场合下的问题有关,而且与当前场合之外的问题也有关。
(2)教学(teaching),这将教会我们去理解怎样对解决方案加以完善,从而适应问题的变体。(对实际使用的模式来说,与教学有关的大部分内容都包含在对问题的描述、对解决方案的描述以及应用模式后得到的结果中。)
(3)一个用来指代模式的名字。
诚然,一个令所有人都满意的定义是很难找到的,从“pattern-discussion”邮件列表(即patterns-discussion@cs.uiuc.edu③)中持续的争论可略知一二。其中的困难在于,模式既是事物又是对相似事物的描述。区分两者的一种方法是,统一使用术语模式来表示描述,用模式实例来表示对模式的具体运用。
但是,定义术语可能只是徒劳无功,因为一个定义也许对一部分受众(如程序员)有用,但对另一部分受众(比如掌管公司财政大权的执行官)来说却毫无意义。当然,我也不会尝试在这里给出一个最终的定义。我只想说,任何一个规定模式的组成要素的定义,除了要讨论问题、解决方案和场合之外,还必须涉及再现、教学以及命名。
误解2:“模式只是行话、规则、编程技巧、数据结构……”
我称这种误解为“不以为然”。诚然,将不熟悉的事物归纳成已知的事物对我们来说是一件很自然的事情,尤其是在我们没有兴趣对不熟悉的事物进行深入研究的时候。再者,用新瓶装旧酒并号称创新的事情我们已经屡见不鲜了。保持警惕是应该的。
然而,“不以为然”并没有经验依据,很多时候它只是基于表面相似性的一种看法,还掺和些许轻视的态度。此外,从来没有什么东西是全新的,其实自从每个人出生起,各种模式就已经存在于他们的脑子里了。新的只是我们开始对模式进行命名并把它们记载下来。
来看看上面这句话。事实上的确存在一些模式行话,比如“模式”(pattern)本身、“推动力”(force)、Alexander的“无名的品质”(quality without a name),等等。但我们很难把模式简单归纳成行话。与计算机科学中的大多数领域相比,模式几乎没有引入什么新术语。事实上这是模式的特征,一个好的模式天生就很容易为它的受众所理解。虽然模式可能会用到它所面向的目标领域的行话,但我们几乎不需要为模式定义专门的术语。
模式不是可以盲目应用的规则(否则有悖于模式的教学特性)。模式也不仅仅是编程技巧,虽说“惯用法”关注的是与特定的编程语言有关的模式。“技巧”在我听起来有些贬义,它过分强调了解决方案,而忽略了问题、场合、教学以及命名。
毫无疑问,一项新事物要被接受会经历三个阶段:第一个阶段,它被当作垃圾,无人问津;然后它好像是不可行,无法推广;最后它变得显而易见,理所当然,人们会说:“我们一直以来都是这么做的。”模式目前还没有完全脱离第一阶段。
误解3:“看到了冰山的一角,就等于看到了冰山的全部。”
以偏概全不是一种正当的做法,如果用这种方式来看待模式,那就大错特错了。模式所涉及的领域、内容、范畴和风格非常广泛,而且它们的质量也千差万别。只要随便翻阅Pattern Languages of Program Design[CS95、MRB98、VCK96] 丛书中的一本,就可以感受到这一点。模式和编写模式的人一样多样,也许有过之而无不及。随便举几个例子,Alistair Cockburn、Jim Coplien、Neil Harrison以及Ralph Johnson等,虽然这些作者一开始也曾尝试用多种风格来为不同领域编写模式,但是现在他们早已经超越了这个阶段。因此,仅仅通过少数几个例子就对模式下一个笼统的结论是错误的。
误解4:“模式需要工具或方法的支持才能生效。”
在过去的5年中,我曾经编写过模式,使用过模式,并帮助过别人使用模式,也参与设计过至少一个基于模式的工具[BFY+96]。我可以很有把握地说,模式的优点来自于对模式本身的应用,也就是说不需要任何形式的支持。
当我在谈论这个话题的时候,我通常会指出模式的4个主要优点。
(1)它们提炼出专家的经验和智慧,为普通开发人员所用。
(2)它们的名字组成了一个词汇表,有助于开发人员更好地交流。
(3)系统的文档若记载了该系统所使用的模式,则有助于人们更快地理解系统。
(4)它们使得对系统进行改造变得更加容易,无论系统原来的设计是否采用了模式。
长久以来我原本认为大部分的优点来自第1点。现在我认识到第2点的重要性不亚于第1点。想一想:在软件开发的过程中,开发人员之间的口头及电子形式的交流的信息量有多少字节?我猜即使没有几吉字节,也有好几兆字节。(在我们编写《设计模式》一书的过程中,我保存下来的我们4人之间来往的电子邮件文件大小达数兆字节之多。我认为我们所付出的精力,差不多相当于开发一个小型到中等规模的软件项目。)交流如此多耗时自然多,任何有助于提高交流效率的东西都将为我们节省相当可观的时间。因此,模式使人与人之间的交流更顺畅高效。随着软件开发项目的规模变得越来越大,软件的寿命变得越来越长,我对第3点和第4点的重视程度也在不断提高。
简而言之,模式是供大脑消化吸收的食粮,而不是供工具加工的材料。方法论和自动化的支持对模式可能会有好处,但我相信这些都只是锦上添花的东西而已。
※ ※ ※
我们到目前为止讨论的误解都与模式是什么有关。现在让我们来讨论一些关于模式能做什么的误解。这些误解有两类:夸大其词类和轻描淡写类。
误解5:“模式可以保证可复用的软件、更高的生产率、世界和平,等等。”
这个误解很容易批驳,因为模式并没有保证任何东西。它们甚至不能增加从中获取益处的可能性。模式并不能代替人来完成创造,它们只不过给那些缺乏经验但却具备才能和创造力的人带来了希望。
人们说到好的模式,会有恍然大悟之感。只有当模式能够触动心弦时,这种情况才会发生。如果模式无法触动心弦,那么它就像人迹罕至的森林中的一棵大树,纵使轰然倒下也没有人能听到它的声音。模式也是如此:即便它编写得再好,如果不能引起人们的共鸣,那么它好在哪里呢?
模式只不过是开发人员军火库中的另一件武器。将太多东西都归功于模式只能适得其反。要防止夸大其词的宣扬引发抵触情绪,最好的方法就是——少说多做。
误解6:“模式可以‘产生’整体架构。”
这种误解与上一种误解很相似,只不过夸张的程度要轻一些。
在模式的论坛里,定期会有一些关于模式的产生能力(generativity)的讨论。我认为,产生能力指的是模式能够创造新行为(ermergent behavior)的能力。这种表述听起来很酷,其意思是模式能够帮助读者解决模式没有明确解决的一些问题。就我所知,还有一些观点认为,真正的产生能力几乎能够自动实现这一点。
对我来说,产生能力的关键在于模式与教学相关的部分,例如,对问题的描述和对解决方案的描述,或对效果的讨论。在定义和提炼架构的时候,这些见解尤其有用。但模式本身并不能产生任何东西,能够产生东西的是人,只有当人具备足够的经验并且他们使用的模式足够好的时候,他们才能够这样做。而且,模式不可能涵盖架构的方方面面。给我看一个稍有规模的设计,我一定能发现既有模式尚未涉及的许多设计问题。也许这些问题不常见或不经常发生,或者只不过它们尚未被编写成模式的形式。但无论如何,我们需要运用自己的创造力来填补各种现有模式之间的空白地带。
误解7:“模式是用于(面向对象的)设计或实现的。”
误解的另一个极端是过分贬低模式的作用,就像现在讨论的这一种。竟然有人会相信这种说法,坦白地说,我对此感到很惊讶。然而有许多人曾经就这个问题问过我,多到足以让它能够在十大误解中占有一席之地。如果你觉得这种误解太过幼稚,那么可以直接跳到下一种误解。
如果模式不能把专家的经验记录下来,那么它们就一无是处。究竟记录哪些经验则由模式的编写者决定。在面向对象的软件设计中,当然有值得记录的经验,但在非面向对象的设计中,同样有值得记录的经验。不仅在设计领域有值得记录的经验,而且在分析、维护、测试、文档、组织结构等领域都有值得记录的经验。这些不同领域中的模式正在浮现。目前在分析模式领域,已经至少出版了两本书[Fowler97, Hay96],而且每一届的PLoP会议都会吸引一些新型的模式。(提交给1996年会议的一个模式特别有意思,它是关于音乐作曲的模式!)
与大多数的误解一样,这种误解也有一定的道理。如果看一看人们使用模式的形式,就会发现两种基本的风格:一种是《设计模式》一书所使用的高度结构化的GoF风格,另一种是Christopher Alexander的近乎纯文学的风格——叙述的文体,采用尽可能少的结构。在我涉足为面向对象设计以外的领域编写模式之后,才认识到GoF风格是多么地偏向面向对象领域。在我尝试过的其他领域,GoF风格根本不适用。对C++惯用法来说,它的结构图应该是什么样的?对音乐作曲的模式来说,它在实现上的取舍应该是什么样?对于用来撰写好的说明文的模式来说,它的协作部分应该是什么样?
显然,没有任何一种模式能够适用于所有领域。唯一能够适用于任何领域的是一个通用的概念——无论在什么领域,模式都是一种用来记录和传播专家经验的工具。
误解8:“没有证据表明模式对任何人有帮助。”
这种误解在过去还能站得住脚,但现在已经不是那么回事了。人们正在通过各种渠道报道模式所带来的好处,这些渠道包括Software—Practice and Experience [Kotula96]之类的期刊,以及OOPSLA [HJE95, Schmid95]和ICSE [BCC+]之类的会议。Doug Schmidt也曾经表示过,模式对大学生和研究生的计算机科学教学有诸多好处[PD96]。虽然这些大多是定性的分析,但就我所知,至少有一个团体正在进行受控的实验,以获取量化的结果。
随着时间的推移,我们会更加清楚使用模式所带来的好处和隐患。即使最初的反馈非常好,我们仍然需要积累更多的经验,这样才能得到一个更加全面的评估。但是,如果仅仅因为模式所带来的好处还没有被完全量化就拒绝马上开始使用模式,那绝对是很愚蠢的行为。
※ ※ ※
关于模式能够做什么的谬论就到此为止。下面最后两种误解与模式本身无关,而与拥护模式的社区有关。
误解9:“模式社区是一个由精英分子组成的小帮派。”
我很想知道这样的想法从何而来,这是因为如果模式社区确实有哪方面值得一提,那一定是它的多样性。这一点很容易判断,只要看一看PLoP的与会者就可以知道——人们来自世界各地,既有来自大公司也有来自小型创业公司,有分析师、设计师和实现者,有学生和教授,还有大名鼎鼎的作者和新手。而且令我感到惊讶的是,有几个经常参加该会议的与会者竟然不是搞计算机的!模式社区仍然处于不断变动的状态,每年与会者的流动率都相当高。
模式社区里常常有著作发表,但社区中有学术背景的人相对来说却并不多,对此有人可能会感到不解。事实上,PLoP的大多数与会者都是软件行业的从业人员,而且似乎一直以来都是这样。软件模式的早期拥护者们(包括Kent Beck、Peter Coad以及Ward Cunningham)没有一个是来自学术界的。GoF中只有一个(Ralph)来自学术界,而且他是我所见过的最讲究实用性的学者。模式社区的草根本质显然与那些所谓的同种论(homogeneity)和精英论是背道而驰的。
误解10:“模式社区是为自己服务的,甚至是不怀好意的。”
我曾经不止一次听到对模式的责难,说模式的主要用途是作为那些编著模式方面图书的人的收入来源。甚至还有一种说法是模式正朝着一个不可告人的方向发展。
完全是一派胡言!
作为GoF中的一员,我可以非常肯定地说,我们4人和其他任何人一样,对于人们对《设计模式》的反响感到惊讶。毫无疑问,当设计模式在1994年的OOPSLA会议上初次亮相时,我们4人对它所引起的轰动效应完全没有心理准备,读者的大量需求甚至让出版社都感到措手不及。在写书的整个过程中,我们最多的考虑就是尽我们所能来创造一本最高质量的图书。为了深入理解模式的内容,我们已经太忙了,根本无暇考虑销售问题。
当时的情况就是那样。现在模式 已经成为了一个重要的术语,因此有些人想利用它来谋取一些私利也在所难免。但是,如果仔细地阅读那些模式领军人物编写的作品,你就会感受到其中共同的宗旨:将来之不易的专家经验、最佳实践,甚至是竞争优势——多年亲身实践所积累的经验硕果——不仅展露出来而且传授给所有后来者。
正是这种要提升所有读者的软件设计能力的热情,激励着每一位真诚而富有成效的模式编写者。缺少任何一项因素,那只能是适得其反,并最终导致对模式的误解。