译者 | 胥磊
审校 | 孙淑娟
软件行业中几乎在每个公司,我们都会听到一些话题的讨论,我相信关于设计模式的争论绝对是其中之一。你甚至可以找到无数的帖子、文章或者Quora和Stackoverflow上的问题的问答无不是在争论设计模式,前些天我就看到了Quora上一个很古老的问题:“为什么现在程序员很少谈及设计模式?哪些模式(如果有的话)依然还有价值?”显然提问者所说的设计模式是面向对象的设计模式,更确切的说是GoF书中介绍的那23种设计模式,当然大多数回答问题的人也都是这么认为的。
“设计模式”这个术语已然成了“面向对象的设计模式”的代名词,所以当你遇到“设计模式已死”的这种奇怪说法时不要感到震惊。在这篇文章中,我们将重新声明下什么是设计模式,这有助于我们在讨论或使用某种设计模式时,能使我们确定我们究竟在谈论或使用的是什么。
1、设计模式对你意味着什么?
让我们抛开所有的书面上的定义和解释,当提到设计模式这个概念时你首先想到的是什么?一个不该被打破的规则?或是一个字斟句酌的学术建议?亦或是又一个的设计约束?还是说一个你只需要知道就能通过求职面试的法宝?
对我来说,设计模式就像我脑海中的喃喃警语,时刻提醒我不要重复造车轮。你可能有过类似的冲动,当遇到一个问题后就想立即找出应对的解决方案,并开始设计/编写程序——如果是这样的话,那么你也是一个重复造车轮的人。设想一下如果已经有一个现成的解决方案,你再去创造一个到头来只是浪费了不必要的时间和精力。尽管这种冲动可能会随着时间的推移而有所克制,但要完全克服这种冲动情绪,我相信设计模式就是“良药”之一。
许多软件工程师应该都碰到过一个相似的问题,因为某些原因都以某种特定的方式解决了它。上述情况同时也提醒了我,这背后可能隐藏了一个道理,启示我们要从不同角度去看待问题,即使我们很少这么干。让我们看一下GoF的书中介绍的一段:
“我们都知道设计经验的价值,但你又有过多少次那种“似曾相识”的感觉的经历——那种你曾经解决过类似问题,但却不知道在哪以及如何解决的感觉?如果你能记住以前问题的细节以及解决的方法,那么你就可以重新使用这种经验,而不是再次去找解决问题的方案”。
或多或少我们都有过类似的经历:当我们无法记住之前的解决方案时,就会出现反复去解决同一个常见的设计问题的情况。设计模式就是重用解决方案去解决反复出现的问题,从而节省了我们的时间和精力,可以转而去做其他事情。现在,让我们深入探讨一些模式的基本概念和定义。
2、模式意味着什么?
什么是模式?模式的概念并不是软件行业所特有的,其他学科和行业如建筑学、经济学等同样适用。让我们来看下建筑学界权威人士克里斯托弗-亚历山大对模式的定义:
“每种模式都是一个由三部分组成的规则,它描述了某种背景、问题和解决方案之间的关系。”(Alexander, 1979)“每个模式都描述了一个在我们的环境中反复出现的问题,然后描述了解决这个问题的核心。通过这种方式,你就可以无数次地使用这个解决方案,而不是用同样的方式做多次。”(Alexander, 1977)
现在让我们看看模式在软件行业的意义。“软件架构的设计模式描述了在特定的设计环境中反复出现的特定的设计问题,并为其提供了一套可行的通用方案。解决方案是通过描述其组成部件、它们之间责任和关系以及协作方式来指定的。”(BMRSS, 96)
基于上述定义,我们可以将模式视为背景、问题和解决方案三者之间的有机结合。它是一个宽泛的概念,可以应用于不同的规模和抽象层次,从设计整个软件系统到解决特定编程语言的设计问题都可以应用。
3、不同的模式类别
模式是根据其规模和抽象程度来分类的:
(1)架构模式
(2)设计模式
(3)习语
架构模式关注的是整个软件系统的架构,它的子系统,不同的大组件,以及它们的结合方式。这种模式是一种高层级的抽象,并不关心编程语言是什么,也不关心使用的是什么框架。
“架构模式描述了软件系统的基本结构的组织模式。它提供了一套预定义的子系统,并规定了它们的责任,其中包括组织它们之间关系的规则和指导手册”。(BMRSS, 96)
另一方面,我们在最低的抽象层次上也有一些模式,称之为习语,它涉及到设计和实现。习语是针对特定语言的,也就是说A语言中的习语在B语言中是不相干的。“习语是一种针对特定编程语言的低级模式。习语描述了如何使用给定语言的特性来实现特定方面的组件或组件之间的关系”。(BMRSS, 96)。在上述那些规模和抽象水平的模式之间,还有一些其他的模式,那就是设计模式。
4、设计模式的近距离观察
让我们回顾一下设计模式的定义:“设计模式为完善软件系统的子系统或组件,以及它们之间的关系而提供的一个方案。它描述了一个相互通信的组件的常见结构,用以解决特定的环境中常见的设计问题”。(BMRSS, 96) 。设计模式属于中等规模,这意味着它们既不像架构模式那样高度抽象,也不像习语那样与编程语言耦合。使用设计模式并不影响软件系统的架构,但它会影响子系统的结构及其较小的组件。
现在让我们来讨论下面这句话(摘自同一参考文献),其中包含了关于设计模式的一个重要事实。“它们往往独立于某种特定的编程语言或编程范式”。(BMRSS, 96) 。根据之前在文章中谈到的模式类别,我们重新表述一下:“它们独立于一种特定的编程语言,但往往(不总是)依赖于一种编程范式。”这句话的第一部分很清楚:如果一个模式依赖于特定的编程语言,那么它就属于习语的范畴。关于第二部分,设计模式是为解决编程范式中出现的常见问题而做出的尝试。它们很可能是对范式的缺陷的应对。例如GoF书中描述的23种面向对象的设计模式,其中大部分都不是函数式编程范式中的关注点。反过来也一样,因为设计模式都有不同的背景。正如你在下图中看到的,不同的范式可以共享设计模式,但我们不打算讨论这个话题,因为它超出了本文的范围。
5、一个著名观点的分析
记住前面的章节,让我们快速浏览一下当你简单地用谷歌搜索设计模式时可能遇到的观点:函数式编程语言不需要设计模式。你可以在这里找到答案,显然这种说法是错误的,因为它暗示设计模式只属于面向对象范式。设计模式是一个在函数式编程范式和面向对象编程范式中都可以存在的概念,设计模式是针对各种范式的问题和需求而设计的。函数式编程范式同样有专门针对其背景的设计模式。此外,正如我们在前几节所讨论的,不同的范式有不同的背景,因此就会遇到不同的问题,我们不应该指望范式B的设计模式来解决范式A的问题。
6、快速回顾
设计模式与其他模式类型类似,试图解决一个特定环境中反复出现的问题。
(1)它们是独立于语言的,但大多是跟范式耦合。
(2)作为中等规模,它们不像架构模式那样抽象。
(3)它们的应用并不影响软件系统的基本架构,但会影响子系统的架构。
(4)最后但也同样重要的是,它们是(所有类型的模式)防止我们重复造轮的手段。
在我看来设计模式并不是约束我们设计的严格规则。它们既不是固定的,也不是无懈可击的,因为它们可以进化,可以变得完善,甚至可以消逝,但模式的概念仍然存在。遵循模式就像是一种思维方式,帮助我们找出可能更好的解决方案。
原文链接:https://dzone.com/articles/a-seemingly-simple-question-what-are-design-patter
译者介绍
胥磊,51CTO社区编辑,某头部电商技术副总监,关注Java后端开发,技术管理,架构优化,分布式开发等领域。