在四人帮(Gang of Four,GoF)的那本设计模式的书出版20年后,重新审视设计模式,书中的23种设计模式,真的只是23种使用指针的方法吗?对我们这个时代是否还有指导意义?(来自湾区日报对本文的评论)
二十年前,软件设计领域的四位大师(GoF,“四人帮”,又称Gang of Four,即Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides)通过论著《设计模式:可复用面向对象软件的基础》阐述了设计模式领域的开创性成果。
当时软件设计仍以C++与Smalltalk为主流,同时利用时间设计理念(例如强调继承)进行编写,但抛开历史的局限、他们已经为业界带来一场规模可观的浪潮。然而历史告诉我们,任何言过其实且无法在实践层面履行承诺的“浪潮”都必然令人失望,并最终遭到淘汰。如今二十年弹指一挥,我们应当重新审视当初提出的23种模式(其中一些亦可被称为变种),考虑它们与二十年来愈发成熟的编程语言还能否契合或者说并发出新的火花。
在模式“运动”发展之初,人们还将其视为一种新鲜的概念,但却很少花时间探讨其究竟是什么。模式就是模式——它来自我们阅读的参考书籍、体现在实践层面的代码当中,亦充斥于我们的日常工作之内。直观地讲,我们似乎意识到自己能够运用这些知识,亦欣赏头脑中孕育出的种种新型模式思路。
Gang of Four(简称GOF)似乎从一开始就将模式视为一种艺术/科学;在论著的最后一章(遗憾的是,读者们大多直接将其忽略),他们指出:
这本书的实际价值也许还值得商榷。毕竟它并没有提出任何前所未有的算法或者编程技术。它也没能给出任何严格的系统设计方法或者新的设计开发理论——它只是对现有设计成果的一种审视。大家当然可以将其视为一套不错的教程,但它显然无法为经验丰富的面向对象设计人员带来多少帮助。
但需要强调的是,实际情况在于:这本书中的模式设计理念尚未彻底完成。我在DevelopMentor上结识的一位朋友将设计模式称为“23种指针使用方法”。好吧,似乎也有道理。
同样的,当管理层/高管团队将这本书甩给新手开发者并希望他们通过阅读实现技能“升级”时,结果也肯定会让他们深感失望。
然而,收益仍是真实存在的,而且更加微妙:
我们希望您能拥有差异化思维。对设计模式进行分类非常重要,这意味着我们能够在相关技术当中使用标准名称与定义。如果不对软件中的设计模式进行学习,那么我们将无法对其加以改进,更遑论创造出更多新模式。
诚然,GOF的这本论著引发了一股浪潮,而这股模式浪潮又催生出远超GOF提出的23种初始模式之外的思维结晶。然而,事情亦开始朝着更为抽象及高层的方向推进,模式开始以“模式语言”的姿态出现,并反过来创造出“元模式”。而后人们开始记录其中的负面因素,并将其称为“反模式”。
一旦人们意识到这一议题能够带来经济收益,相关出版物亦开始不断涌现。
各类出版商不断推出“模式“方面的书籍——但这些出版物几乎根本不涉及GOF提出的原始模型。模式书籍成了”可复用代码“(而非‘可复用设计元素’)的代名词。IDE供应商开始寻找可行途径,希望将多种模式整合为代码生成器。同样莫名其妙的是,模式也开始成为UML及其它设计符号的载体,其目标被误解成弄清如何在UML当中找到与模式相对应的可复用设计模板。
与众多炒作对象一样,模式成为一种潮流,但人们并不知道其核心吸引力究竟是什么。在这种情况下,模式概念显然没办法满足人们的预期。
到2000年中叶,模式开始成为一种负面概念,当时的宣传导向则转为“捣毁“模式——即强调模式属于“糟糕语言”加“原始思路”再加上“被归入优秀语言”的综合体。
但是……模式这一称谓仍然不断出现,直到今天我们亦在大量使用。为什么?GOF实际早在1995年就对此做出了预言(同样来自书中最后一章):
“设计模式为设计师们提供一种共通的词汇储备,帮助其沟通、编写文档并探索设计方案。设计模式允许我们立足于高级抽象层面进行探讨,而非设计标注或者编程语言,这就大大降低了系统复杂性。设计模式提升了我们设计及与同事进行设计探讨时的切入点层级。”(第389页)
“理解本书中的设计模式能够帮助大家更轻松地掌握现有系统。……人们在学习面向对象编程时,往往会对需要面对的系统抱怨不休,包括其要求以令人费解的方式实现继承且难以追踪并控制工作流。之所以出现这些问题,很大程度是因为他们并不了解系统的设计模式。了解这些设计模式能够帮助各位更好地掌控现有面向对象系统。”(第389页)
“设计模式提供了一种既能解释决策结果,又能解释设计“理由“的方式。设计模式的适用性、结果性与实现部分能够引导大家做出更为明智的决策。”
“在开发可利用软件时,一大问题在于其往往必须进行重构或者重组[OJ90]。设计模式能帮助大家了解如何对设计进行重组,并降低日后需要面对的重构工作量。”
(是的,他们早在业界将其视为时尚之前,就已经提出了重构的必要性。)
最重要的是,他们还准确预测出了模式弊端所引发的问题:
“人们很容易将模式视为一种解决方案,或者说一种能够进行实际采纳及复用的技术。相比之下,人们很难弄清其更为确切的核心——即定义其能够解决的问题以及在哪些背景下才属于最佳解决方案。总体来讲,大多数人都能弄清他人正在做什么,却不太了解这样做的理由——而所谓”理由“对于模式而言正是其需要解决的主要问题。理解模式的目标同样重要,因为这能帮助我们选定适合自己的模式,也能帮助我们理解现有系统的设计方式。模式作者必须弄清并定义该模式所能解决的问题,或者至少在将其作为解决方案之后做出进一步思考。”(第393页)
很多短视的从业者将模式视为“解决方案”,并一窝蜂地希望找到可复用代码,但却忘了(或者刻意不去想)“理由”是什么。作为结果,他们往往会犯下一些非常愚蠢——但本该能够轻易被预测——的错误。
多年以来,围绕这一议题出现了无数讨论,但我想用下面这句话对其加以概括:
就是这样。没什么神奇、神秘或者超学术性质的元素。如果大家能够对元组的全部四个部分加以描述,那么这就是一种模式。把它写下来再加以发布。
一旦发现了彼此之间的共同点,我们就可以从中找到共性所在,而后为其选定一个合适的名称并加入到通用词汇表当中。
Gang of Four发布了23条这样的模式,当然模式的实际数量远不止如此。大部分模式都极具实用性,但实用性最出众的还是这最初的23条——因为它们涵盖了众多不同类型的编程语言。(模式业界后来创造出了所谓‘成语’,其只适用于特定的语言。因此来自C++的‘资源获取即初始化(简称RAII)’概念就成了与C++语言紧密相关的‘成语’,而并非真正的模式。)
不过最后一句又带来新的问题:模式业界投入了太多时间进行讨论,包括模式本身、特定对象是否属于模式乃至某种特定代码片段到底属于哪种模式的具体实现方式等等。
在这方面我们有两种基本思路:
围绕模式展开的哲学辩论对切实实现其收益而言非常重要。正因为如此,模式业界才会提出“某种对象至少要出现三次才能被称为模式”以及“未曾出现在模式会议上的成果根本不能被称为模式”等论调。其重点并不是为模式添加神秘色彩或者不可知论要素,而是探讨如何从哲学层面定义模式的实质并保证其质量水平。一旦人们对这种作法嗤之以鼻并加以回避,那么可以想见,一切疑似模式的事物都将被粗暴地视为模式。如果突然之间,我们开始将本地变量称为“模式”,那么设计高级工具集的意义将不复存在。如果任何人都能够根据自己的理解将任意对象称为“模式”,那么模式也就失去了其在交流中的作用。科学具有严谨性,而严谨性正是模式业界最为需要的特质。
实际使用哪种模式并不重要,或者说只是一种哲学层面的讨论。很多人都喜欢跟团队中的其他成员争论某些代码到底属于哪种模式。我实在想不到还有比这更无聊的行为了——除非这类讨论能够围绕模式带来什么新启发(例如新的应用方式或者新的审视角度)。总之,这种作法甚至会影响到人与人之间的友好关系。
模式并不是优秀设计的全部或者必要标准。 大家完全可以鼓捣出一套出色但却完全不符合任何现有模式的设计方案。模式的拥护者们,请不要再拉着这面大旗对身边的一切品评不休了。
最后需要强调的是,模式的拥护者本身可能正是导致模式毁灭的导火索——但事情仍然还有转机。
我想在模式概念首次出现的二十年后,是时候对其进行重新讨论了。我无法想象自己如何凭一己之力重现这样的浪潮,但至少我可以对过往的积累加以整理,留其精华而去其糟粕,并期待将其引入二十一世纪大家所熟悉的各类主流语言。在这一过程中,也许我们还会发现更多新的模式,我亦会从中选择部分合适的与大家分享。
在未来几个月中,我将立足于“现代世界”对这23条元祖模式进行回顾,并采取我个人最喜爱的审视方式(问题/解决方案/背景/结果)。我不会直接引用太多来自Gang of Four论著中的原文,因为这会构成侵权行为——但我强烈建议大家买一本自行阅读,并借此思考我给出的结论是否合理。另外,我还会以部分现代语言为基础探讨各类模式的实现方式,具体包括:C++、C#、Java、Swift、F#、Scala以及JavaScript等等。我绝对不是世界上最聪明的家伙,所以肯定没法以最为纯熟的方式运用这些语言并探讨其相关成语适用性——因此请大家积极发表意见与建议,以帮助我完成修改/更正。另外,我也希望能够与大家共同涵盖全部主流(可能也会包含部分并不那么流行但有助于指导效果的语言)语言。
这些工作都需要时间,所以请大家多多包涵。我会尽快再发布一篇博文讨论具体细节,而在此期间希望大家能买一本GOF的《设计模式:可复用面向对象软件的基础》来读读。
后记:作者做的工作非常有意思,在我和他发邮件申请本文的版权的同时,他也诚挚的邀请中国的开发者能和他做这个有意思的探索。的确,设计模式已经存在了几十年,很多东西已经不再适用,但这些模式已经被当做开发领域的金玉良言。是时候来反思了!
点击阅读原文链接,查看作者对Java的单例模式的论述,如果感兴趣,欢迎评论留言,和Ted一起回顾设计模式。
本文经Ted授权翻译,原文地址:http://blogs.tedneward.com/post/reclaiming-design-patterns/