四人帮是否彻底探索了“模式空间”?


144

自从我至少在10年前首次了解四人一组(GoF)设计模式以来,我一直以为这23种模式应该只是更大的东西的小样本,我称之为模式空间。假设的模式空间包括针对常见的面向对象软件设计问题的所有推荐解决方案(已知或未知)。

因此,我期望已知和记录在案的设计模式数量会大大增加。

它没有发生。GoF书问世20多年来,Wikipedia文章中仅列出了12种其他模式,其中大多数都不如原始模式流行。(我未在此处包括并发模式,因为它们涉及特定主题。)

是什么原因

  • GoF模式集实际上是否比我想象的更全面?

  • 寻找新模式的兴趣下降了吗,也许是因为发现它们在软件设计中并不是那么有用?

  • 还有吗


49
模式无处不在,但通常以无味和机器人化的方式使用。因此,我认为模式目录的想法变得不那么流行了。
usr

6
设计空间?有人让马克·罗斯沃特(Mark Rosewater)来到这里!
corsiKa

16
马丁·福勒(Martin Fowler)于2003年发布了《企业应用程序体系结构模式》,记录了大约50种模式,其中许多模式如今仍可很好地重新构造和使用,例如“数据映射器”,“插件”,“延迟加载”,“服务层”等。
布赖恩·罗杰斯

2
探索所有可能模式的空间就像根本不探索可能模式的空间。您可以使所有内容成为一种模式。如果您将所有内容都做成模式,那么什么都不是模式,因为单词失去了它的含义。
HopefulHelpful

4
@BradThomas:当然,像最有趣的问题一样,人们倾向于有一定的见解。但是观点至少部分基于事实,我在这个问题的答案中发现了许多有趣的事实,这些事实将有助于我自己,并希望其他人重新考虑他们的观点并获得更多依据。
Frank Puffer

Answers:


165

当《书》问世时,很多人都这样想,并且为创建“模式库”甚至“模式社区”付出了许多努力。您仍然可以找到其中一些:

但是之后...

寻找新模式的兴趣是否下降了,也许是因为它们在软件设计中并没有那么有用吗?

这非常 设计模式的重点是改善开发人员之间的沟通,但是,如果您尝试添加更多的模式,则会很快达到人们无法记住它们,忘记它们,或者对它们的真实外观不同意见的地步。实际上没有改善。GoF模式已经发生了很多事情。

就我个人而言,我会走得更远:软件设计,尤其是优秀的软件设计,变化太多,无法以模式有意义地捕获,尤其是在人们实际上可以记住的少数模式中,而且它们对于人们来说太抽象了真正记住的不只是少数。因此,他们没有太大帮助。

太多的人迷上了这个概念,并试图将模式应用到任何地方–通常,在生成的代码中,您找不到所有(完全没有意义的)单例和抽象工厂之间的实际设计。


50
有争议的意见:无论如何,抽象工厂是一种代码气味:)
MetaFight

66
也许是有争议的观点,但是表达起来非常重要。设计模式有可能成为皇帝新衣服的典范,在那里我们所有人都不敢怀疑它们是否有用。做得好。
David Arno

18
@MetaFightControversialDesignPatternOnlineOpinionHumanReadableRetortFactory.newInstance().getText();
corsiKa's

11
设计模式的重点是改善开发人员之间的沟通 ”我认为设计模式是为了解决开发人员通常(而且通常是独立地)遇到的问题。标准改善了沟通,由于波动(由于XY问题而产生的图案,图案被视为反图案),许多人都不认为设计图案是标准。设计模式擅长指出语言功能的不足,我相信语言设计师会在解决这些问题之前将其变为设计模式。不过,请不要相信我的话
Vince Emigh '16

11
@ChrisW我看不出你的意思...正如我说的,GoF试图克服OO的缺点,尤其是C ++ 98的缺点,因为这是他们与Smalltalk一起选择的语言。他们实际上写道:“编程语言的选择很重要,因为它会影响一个人的观点。我们的模式假定使用Smalltalk / C ++级别的语言功能,而这种选择决定了可以轻松实现的内容。”
Shautieh

108

我的印象是这23个模式应该只是更大的东西的小样本,我称之为模式空间。

这是新手程序员到处传播的可怕假设,程序员认为他们仅通过将软件模式结合在一起就可以编写程序。那样行不通。如果存在这样的“模式空间”,则可以假定其大小实际上是无限的。

设计模式(就GoF而言)只有一个目的:弥补您正在使用的编程语言的不足。

设计模式既不是通用的也不是全面的。如果您更改为其他更具表达性的编程语言,GoF书中的大多数模式将变得既不必要又令人讨厌。


40
“设计模式(在GoF意义上)仅具有一个目的:弥补您所使用的编程语言的不足。” 我一直在听,但是还没有看到合理的理由。每种假设的辩解都指向少数几种具有某些功能的语言更易于实现的模式(通常是Visitor或Singleton),并且使绝大多数模式保持不变,这意味着它们也可以通过以下方式变得多余更好的语言。但是我们怎么知道?什么语言功能使观察者无关紧要?责任链?综合?
Jules

56
@Jules仅一流的功能就消除了它们的很大一部分,包括责任链(它只是功能列表的组合)。功能性反应式编程消除了观察者模式。Composite模式只是对monoid的较不严格的定义,具有类型类并且关注代数律的语言为使用monoid提供了强大的工具。我可以列出更多,但您知道了。
杰克

12
@Jules:我相信原始的GoF书将迭代器作为一种模式列出,但是现在,它在每种OOP远程语言中的语言功能转换已基本完成。
凯文

9
@RubberDuck如何使样式已经实现而使样式过时?仍然是正在实施的设计模式。语言功能的不同集合可能导致模式的不同实现,但是模式本身仍然存在。通过为常用的重复策略命名,可以简化通信方式。以防万一,.NET类的调用ObservableSomething<T>使它易于理解,因为它使用了众所周知的模式名称。模式是一个想法,而不是确切的实现。
空值

29
@Jules:什么是程序?重现问题的解决方案。什么是设计模式?重现问题的解决方案。为什么不是程序?因为我们无法将其表示为程序。因此,设计模式是针对重复出现的问题的解决方案,该问题应该是程序而不是设计模式,但不能是程序,因为该语言的表达能力不足以表达该程序。示例:不久前,“子例程调用”是一种设计模式!如今,它是一种语言功能。
约尔格W¯¯米塔格

61

我认为这里涉及三个因素。

缺乏临界质量

首先,模式基本上只不过是为实现特定“功能”的某些代码命名。名称提供真正价值的唯一方法是,如果您可以依靠每个人都知道名称的含义,那么仅通过使用名称,他们就可以立即对代码有很多了解。

模式从来没有建立完成这些任务所需的临界质量。相反,AAMOF。自GoF书问世以来的20年左右的时间里,我敢肯定我没有看到多达十二次对话,每个参与其中的人都真正了解足够的设计模式以用于改善沟通。

简单地说:设计模式失败是因为它们失败了。

模式太多

我认为第二个主要因素是,如果有的话,它们最初会命名过多的模式。在相当多的情况下,模式之间的差异非常细微,几乎无法确切地确定某个特定类别是否适合一种模式或另一种模式(或可能两者-或两者都不适用)。

目的是您可以在更高层次上讨论代码。您可以将相当大的代码块标记为特定模式的实现。只需使用该预定义的名称,每个倾听的人通常都会对他们所关心的代码有足够的了解,因此您可以继续进行下一步。

现实往往恰恰相反。假设您正在开会,告诉他们这个特定的班级是一个Facade。会议中有一半人不知道或早已忘记确切的含义。其中之一要求您提醒他,门面与代理之间的确切区别。哦,这几位真正了解模式的人在会议的其余部分中讨论了是否应将其真正视为门面还是“仅仅是”适配器(那个家伙仍然坚持认为对他来说似乎是代理人)。

鉴于您的意图实际上只是在说:“此代码不是很有趣;让我们继续前进”,尝试使用模式名称只会增加注意力,而不是价值。

缺乏兴趣

大多数设计模式并没有真正处理代码中有趣的部分。他们处理类似的事情:“如何创建这些对象?”和“如何使该对象与那个对象对话?” 记住这些的模式名称(以及前面提到的有关细节之类的论点)仅仅是为大多数程序员不太在意的事情投入了很多精力。

换句话说,模式处理许多程序之间的相同问题,但是真正使程序变得有趣的是它与其他程序的不同之处。

摘要

设计模式失败是因为:

  1. 他们未能达到临界质量。
  2. 模式之间的差异不足以保证清晰度。
  3. 他们主要处理几乎没人真正关心的部分代码。

2
“ ...但是真正使程序变得有趣的是它与其他程序的不同之处。” 我完全同意,但是为此您必须首先正确处理相同的部分,也许它们只是在一些琐碎的方面有所不同。如果您放松一点,则需要说出名称和识别模式,我相信几乎每个人都会看到模式。只是它们几乎永远不会以其纯粹的形式出现,而总是或多或少地适应当前的问题。
Trilarion '16

5
很好的答案。
罗伯特·哈维

4
@Trilarion:哦,我知道必须编写代码的那些部分。例如,它们有点像您汽车上的轮胎。您几乎完全需要轮胎来驱动-但是大多数人仍然几乎不知道汽车上轮胎的品牌。这要求他们为带有不对称斜槽的轮胎学习特殊术语。谁知道-那些人可能曾经挽救过我的性命,但我仍然不花一生为他们学习名字。
杰里·科芬

3
@DavidRicherby:好的,让我们使用类比的“生产者端”版本。为固特异公司设计轮胎的约翰在那种凹槽上使用一个词是否重要,而为米其林工作的皮埃尔使用一个完全不同的词是否重要?一个人只使用一个凹槽,而另一个人使用一个完整的轮胎,在中心一侧有水平凹槽而在另一侧有对角凹槽,这是否重要?
杰里·科芬

2
@immibis:我大多会说,他们失败了。我想说大多数程序员所识别的模式只有不到六种。Singleton是众所周知的,但实际上很少适用(最多)。“工厂”这个名字是普遍使用长的“模式”来了一起(我记得它在1970年代末或使用前非常 80年代初)。模式应该被用来形成词汇,但是目前它们就像我的希腊语词汇一样-足以(可能)使自己陷入困境,但肯定不足以下单,更不用说进行有意义的对话了。
杰里·科芬

35

模式缺少抽象,抽象了简单的模式,无法识别复杂的模式,因此模式没有用(除了一些高级模式)。

我认为Paul Graham说得最好:

当我在程序中看到模式时,我认为这是麻烦的迹象。程序的形状应仅反映需要解决的问题。至少对我来说,代码中的任何其他规律性都是一个信号,即我使用的功能不够强大-通常是我手工生成需要编写的某些宏的扩展。

当您识别代码中的模式时,这意味着某些内容会重复出现,您应该使用更好的抽象。如果没有更好的抽象,则可以使用该模式作为解决方法。因为较新的编程语言提供了更好的抽象,所以模式的用处大大减少。
同样,简单模式通常很容易抽象,而复杂模式却很少被认识到。
当某个模式被抽象替换时,这并不意味着该模式背后的概念就消失了,而是该概念可以显式地写成间接的,而不是间接的,并且与其他代码相比,它不再特殊,并且不再可以识别为一种模式。


2
我个人真的很喜欢这个主意。但是,代码应该像人类一样被人类和人们阅读。模式可以帮助我们找到解决方法。从我们的代码中删除所有模式将使其不可读。
Frank Puffer

2
@Frank我认为PG的来源是模式是您可以抽象的底层函数的“气味”,而您没有将其提取到函数或宏中的事实就是造成重复的原因-就像如果您没有String.replace功能,则可以想象它会以一种模式弹出,但是最好只编写一次,而不是继续重新实现。同意如果您没有正确命名这些名称,将使其更难阅读,但正确完成后,代码将以更具声明性的getOrElse方式读取IMO(例如,选项monads与null检查的样式)
anotherdave

11
保罗·格雷厄姆(Paul Graham)的报价是关于保持解决方案干燥的,这不同于GoF“模式”的想法。GoF的想法是为常用的解决方案命名。在GoF发布他们的书之前,我们已经做了那么久。例如,我可以告诉我的同事我要使用队列,而我的同事可以立即知道我在说什么,而无需解释队列的作用或工作原理的细节。但是,请参阅上面的Michael Borgwardt的出色答案。
所罗门慢

10
我认为,该答案误解了什么是模式。设计模式是常见问题的常见解决方案。这不是一些代码重复。假设有一个迭代器。您解决了将容器抽象化的问题,因此无论容器是什么,都可以遍历其中的元素。因此,您将创建一个迭代器类,该迭代器类为每个容器执行此操作,并使它们实现一个公共接口。这里要抽象什么?迭代器已经是一个抽象。而且,当然,所有容器的实现方式都不同,因此没有代码重复。
马尔科姆

3
Graham引用的关键部分通常是我手工生成需要编写的某些宏的扩展。这专门引用了Lisp宏。没有宏,只能做很多抽象工作。
巴特·范·尼罗普

13

尽管我在很大程度上同意其他人在此处回答的内容,但我个人认为,模式数量没有增长的主要原因是,当存在无数模式时,模式就会失去其含义。这几种模式的好处是,它们以标准方式涵盖了很多问题领域。如果您专注于无止境的模式域,那么最终将根本没有任何模式。有点像“一个岛的海岸线有多长?”。如果在地图上测量,您会得到一个不错的数字。但是,如果您尝试获得更高的精确度并获得更高的分辨率,您会发现长度越来越多地达到无穷大(或不确定性;您将如何在潮汐和原子水平上测量精确的边界?)。


1
是的,模式只有在模式太多的情况下才能起作用。但是,为什么GoF仍然是最受欢迎的?现在,许多人(Singleton,Builder等)将其中的一些视为反模式。这应该为新的,更有用的模式腾出空间,而不增加总数。
Frank Puffer

2
我想这就像十诫。来源仅2个字符(GOF,GOE,GOD)xD
qwerty_so

9
是的,有时似乎现代软件工程与GoF有关,就像中世纪的学者与Aristotle有关。
Frank Puffer

11

其他答案均未提及的相关内容:

动态类型语言的兴起。

当这本书第一次来到外面有认真的讨论是Java的是做。现在的Java真正的工作实在是太慢了,经常使用在更具表现力的语言,因为它的速度。对于某些重要的应用程序类来说,也许Ruby,Python,JavaScript等仍然太慢,但总的来说,它们对于大多数用途来说足够快。尽管每个版本中都包含了更多功能,但至少JavaScript实际上正在变得越来越快。

最初的GoF书籍在smalltalk和c ++中都具有模式,并且如果有内存服务,则在smalltalk中,模式总是会更短,有时甚至会明显缩短。经典设计模式的某些功能实际上是向静态类型的系统中添加动态功能的方式(例如已经讨论过的AbstractFactory,您可以在其中基于运行时数据实例化正确的类)。其他人在动态语言中要短得多,以至于他们只是简单地融入了语言本身的惯用用法。


10

没有发生。出版了数十本甚至数百本的书,这似乎是一种试图将整个计算机科学简化为设计模式的尝试,因为出版商和作者试图跳入(或创造)另一种潮流。我有一个架子。自从第一次扫描以来就再也没有进行过咨询,是的,我是个傻子,因为其中几乎没有或没有任何实际用途,或者尚不为人所知(例如参见Type Object,它不过是表示为一打页面而不是一个段落),因为显然模式越少越好:这是大多数实践者无法理解的一点。确实,当我发表对Type Object的反驳时,我被指示要重铸我的文本作为一种设计模式。真实的故事。这也显示了该项目的另一个缺陷:没有审查,排除或拒绝机制。

实际上,GoF实际上并没有尝试“彻底探索设计模式”。相反,他们从事的是一个更大的项目:将“模式语言”引入到CS中,以其所有奇异的符号化的力量,参与者等奥秘名言,只是失败了,因为它从根本上被误解了,并且毫无意义。

他们什么做到,这是有用的,是两件事情:

  • 发布一些有用的技巧,例如“访客”模式
  • 提供一组标准的名称,这些名称在很大程度上已经卡住了:Factory,Adapter,Iterator等。...如果您看一下预先设计好的CORBA,您将看到它的价值:各种“外国”名称,例如Interceptor ,仆人,经纪人,...

出现的另一个有用的概念是“反模式”,例如“对数并抛出”。与CS的许多时尚一样,该项目因其自身的传教活动以及被误导为另一种CS宗教而脱轨,并且沿着大多数此类宗教的道路发展:在某些方面有用,但肯定是``没有灵丹妙药''((c (弗雷德·布鲁克斯,1965年)。遗憾的是,我们必须每隔几年才重新发现一次。


如果它引发了这场讨论(还包括所有这些内容),是否仍然感到难过
r3wt

1
@ r3wt 非sequitur。我很难过的是,IT行业的弱点在于认为每个新开发都将成为神话般的灵丹妙药,并且偶然地浪费了一些自己的先前工作。
user207421

2
从不同的角度来看它。对我来说,阅读您的答案,学会不重蹈覆辙并不难过。因此,您理所当然的事情对其他人非常有用。
r3wt

6

有/几本标题为PLoP(程序设计的模式语言)的书,都是在年度会议上发表的论文选集。

读这些书后,我发现有些模式对我来说很有趣并且是新奇的,其中有些是标准的(例如“半对象加协议”)。

因此,不是的,GoF的收藏并不详尽,并且启发/启发了人们收集/描述/发现/发明新的收藏。

“ Wikipedia文章中列出的仅12种其他模式”可能也不是完整的集合:即在其他地方(例如PLoP书籍中以及其他地方)也有其他文献记录。


是的,如果您搜索数百种模式,则可以找到它们的描述。但是这些似乎都没有像GoF那样受欢迎。
Frank Puffer

这是因为我喜欢阅读GoF书籍,所以在出版(后来)时,我阅读了更多(书籍)。
ChrisW

1
@FrankPuffer我敢打赌这些模式很受欢迎,即使名称不是。
dcorking

5

《四人帮(Gang of Four,GoF)》一书包含了大多数模式,这些模式是经验丰富的无功能语言程序员在其工具带中拥有的。就像所有构建者都知道如何使用的基本工具集一样。本书的主要贡献是为当时大多数有经验的程序员常用的模式赋予明确的名称,从而帮助讨论设计方案的程序员之间进行交流。

您希望电工拥有一些普通建造者没有的工具,同样,您希望WPF程序员知道“ Dependency Properties”的设计模式,或者“ SQL Programmer”知道使用触发器的设计模式。创建审核数据。

但是,由于它们仅与一种技术一起使用,因此我们不将它们视为“设计模式”。

另外一些现代的设计模式书是“重构,改进现有代码的设计(Martin Fowler)”“清洁代码:敏捷软件技巧手册(Robert C. Martin),这两本书都介绍了您进行的转换内容到您当前的代码,而不是“罐头可重用设计”,但是它们同样是“设计模式”。


3

这是对Erich Gamma的采访,他回顾了他们对模式的选择以及它们今天将发生的变化(10年前的今天,哈哈)。

http://www.informit.com/articles/article.aspx?p=1404056

拉里:您将如何重构“设计模式”?

Erich:我们在2005年进行了此练习。以下是我们会议的一些笔记。从那时起,我们发现面向对象的设计原理和大多数模式都没有改变。我们想要更改分类,添加一些新成员,并删除一些模式。大部分讨论是关于更改分类,尤其是要删除的模式。

在讨论下降的模式时,我们发现我们仍然喜欢它们。(不完全是。我赞成放弃Singleton。它的使用几乎总是一种设计气味。)

因此,这里有一些更改:

  • 解释器和Flyweight应该移到一个单独的类别中,我们称之为“其他/化合物”,因为它们实际上是与其他样式不同的野兽。工厂方法将推广到工厂。
  • 类别为:核心,创新,外围和其他。这里的目的是强调重要的模式,并将其与不常用的模式区分开。
  • 新成员是:空对象,类型对象,依赖注入和扩展对象/接口(请参见《程序设计3模式语言的扩展对象》,Addison-Wesley,1997年)。
  • 这些是类别:
    • 核心:组合,策略,状态,命令,迭代器,代理,模板方法,外观
    • 创新性:工厂,原型,生成器,依赖项注入
    • 外围设备:抽象工厂,访客,装饰器,介体,类型对象,空对象,扩展对象
    • 其他:Flyweight,口译员

你为什么要鄙视我?请在评论中说明,以便我改善答案。
akuhn '16

3

本书中的实际模式有时确实很有用,但它们实际上只是本书为您提供的功能更强大的工具的一个实例:对何时何地深入将整体代码切成由接口分隔和控制的独立部分更好的深刻理解。 。

学习该技能时,您会意识到您无需记住每个模式的确切细节,因为您始终可以以最适合其目的的方式削减正在实施的解决方案。因此,写下越来越多的模式的想法似乎非常学术性和毫无意义。


好点,但是,我怀疑许多人都以这种方式理解这本书(或一般的模式)。
Frank Puffer

@ lud1977如果我们不记录历史,那么什么能防止未来陷入同样的​​陷阱?因此,必须始终对其进行记录。它不是没有意义的。
r3wt

2

因此,我期望已知和记录在案的设计模式数量会大大增加。

它没有发生。GoF书问世20多年来,Wikipedia文章中仅列出了12种其他模式,其中大多数都不如原始模式流行。(我未在此处包括并发模式,因为它们涉及特定主题。)

GoF书和Wikipedia并不是已知设计模式的唯一来源。如果您仅在Amazon.com中搜索“设计模式”,则可以获得数百本书(尝试使用此搜索)。我猜他们只会在Wikipedia文章中列出最知名的模式。

因此,问题不在于没有足够的书面设计模式。而是有太多的东西,没有人能记住全部,而且大多数程序员只认出其中的几个。在这一点上,通用模式语言的巨大希望破灭了。


-1

可能尚未想到很多结构。只要人们在开发软件,就会面临设计挑战。其中一些可以使用其他人可以利用的聪明的新模式来解决。

编程语言已经发展并进步为抽象出最常用的模式。这些模式在语言设计中仍然存在。因此,它们今天可能会被忽略,但这并不意味着它们不重要。

一旦我们有了可以为我们做的机器人,如何建造房屋的知识就突然变得不重要了吗?我会说不,不是。毫无疑问,它的意义不大-因为需求确实急剧下降,而且没有人在研究它,所以学习的回报可能会少很多。

因此,不,我不认为您所称的模式空间已经用尽。另一个答案指出,它可能是无限的。但是随着对系统设计的需求下降,随着我们增加抽象塔的高度和编程语言的力量-越来越少的高层建筑人员将关注塔的建造细节。


-2

模式是无限的。您可以调整每个模式或混合n个匹配项以创建新模式。.企业集成模式也得到了很好的定义。每个领域的模式都会演变,它们也会随着诸如python或scala之类的表达语言而变化。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.