设计模式真的是语言的弱点吗?

45

今天的模式应该被视为Java和C ++中的缺陷还是缺失的功能?

  • 子例程是50年代和60年代机器语言的设计模式。
  • 面向对象类是70年代C语言的设计模式。
  • 访问者、抽象工厂、装饰器和外观是今天Java和C ++的设计模式。

    明天的语言会是什么样子?它们将有哪些模式?

12个回答

54
一些经典的设计模式,例如Adapter、Factory、Command、Visitor等,是其他语言中内置功能的近似实现。以下是我能想到的例子:
- C#中的事件处理程序是观察者模式的内置版本。如果每次都需要自己编写观察者模式来连接C#中的事件,那会是怎样的体验呢? - Visitor模式是multimethodsmessage forwardingpattern matching的冗长近似实现。 - Command模式将特定的行为封装起来,以便在方法之间传递对象,这更或多或少地近似于一级函数。 - Strategy模式允许您动态地将行为插入对象中,因此您可以随时通过用另一个行为替换一个行为来修改对象。在函数式编程世界中,我们称之为函数组合。 - 抽象工厂模式接受一个参数并返回一个工厂作为结果。通常,您可以将工厂视为一个函数的包装器(更具体地说,是构造函数的包装器)。因此,您将参数传递给函数并获得一个函数作为结果,使得该模式与柯里化相当类似。 - 装饰器模式允许您在运行时附加或删除对象的行为。在JavaScript中,由于“原型”面向对象模型的存在,您可以添加或删除函数而无需显式实现装饰器模式。

所以,我们有一堆设计模式来模拟其他语言固有的特性。特征嫉妒并不一定表明语言的弱点——需要一遍又一遍地编写样板代码才表明语言的弱点。


1
我真的很喜欢这个答案。它表明一些命名模式已经在日常使用中谦虚地存在。这让我想到,“好的,这是明天超级语言的特殊模式集合”。 - Ewan Todd
3
“明天的超级语言”不能来自于今天的语言。它必须是相当不同的——否则我们只会使用今天的语言加上一些扩展。 - S.Lott
2
@S.Lott: “明天的超级语言”可能会在技术奇点的转折点出现,并且正如我所想象的那样,将使所有设计模式过时无用 ;) - Juliet
2
我也非常喜欢它。最后一句话可能是对这个问题最好的回答。而且我从未想过工厂-工厂是柯里化的一种极其冗长的形式。 - Chuck
1
@Juliet:没有什么能使设计模式过时。每当你重复某些东西,那就是一种设计模式。这在所有领域中都经常发生。 - S.Lott
@S.Lott 一种好的编程语言的标志是,经常需要完成的任务非常简单明了。考虑一个压缩算法 - 使用完美算法压缩的文件没有模式; 它全部都是信息。 - Brilliand

18

我不会称它们为缺陷。

高阶语言处理的概念比低阶语言更高级。可以用建筑术语来解释。

您可以在炼油厂水平上建造建筑物,制材、冶钢,并以此方式组装建筑物。

您可以购买木板和钢梁,并将其构建成建筑物。

您可以购买预制墙板和桁架,并将其构建成建筑物。

您可以购买一个建筑物,并直接从内部开始。

使用木板和钢梁构建建筑物是否缺少预制墙板特性或存在缺陷?


通常在谈论模式时,你只是在使用相同的设计,但每次都必须自己编写整个代码。我认为与预制物的类比不成立...那将使用库(当然没有什么不好的)。 - 6502
1
我的观点更多地涉及到当模式被固化到语言中时。例如,当你不必从头开始编写观察者模式时,这有点像在建筑中使用预制组件。但这并不是一个完美的比喻,我同意你的看法。 - Matthew Vines

12

在软件设计中,每个你做三次或更多次的事情都会形成一种模式。

每次重复。每次重复。每次重复。

有些模式被赋予了酷炫的名字,它们成为设计模式。这是有意识的重复。

有些只是“最佳实践”或“这对我有用过”,这些是没有清晰性的设计模式。

有些只是“通常要做的事情”,这些是没有任何自觉认识到自己正在重复的设计模式。

设计模式与语言弱点或不完整无关。它们与好的想法有关,是有意识地重复利用。

今天的设计模式并不是未来语言的王路。语言范式不是通过“修补先前语言的漏洞”这样的方式推进的。如果是这样的话,我们永远不会创建Visual Basic。

而且设计模式是一种比简单的编程语言特性更广泛、更大的智力工具。


好的,但是你回答了他的问题吗? - Robert Harvey
我本以为我已经做到了,但我编辑了我的答案,以更加强烈地表达我的观点。 - S.Lott
我认为这是一个很好的观点。似乎更多的情况是,许多更为知名的(主要是GoF)模式在其他语言中是多余的。 - lukerandall

2
我曾经在某个地方读到过类似于“你拥有的模式越多,你的语言就越不强大”的说法,我觉得这个定义非常好。
原因很明显:如果你看到一个重复的模式(或者必须使用它),那么在逻辑层面上它就是一种复制粘贴。当然,它不像语句的复制粘贴那么糟糕,但它仍然是冗余的。我还在一遍又一遍地重复自己。
语言表达能力越强,你就越能够通过将冗余转化为重用来捕获和提取它,并且在源代码中,重用会更容易阅读和理解。
每当你发现自己再次做同样的事情时(包括例如“好的...让我们在这里实现一个抽象工厂”),这意味着这是应该以更高层次表达的东西。
当然,有时候你可以尝试捕捉某些东西的本质,但是重用可能比重新实现更难读懂(例如,我在想C++“高级”部分中的一些<algorithm>)。这在我看来是语言表达能力不够的明显标志。

2
不,它们不是语言的缺失功能或缺陷。但是,语言应该提供一种编写有用模式代码的方式,这样会更容易而不是困难。这就是语言所提供的功能可以成为福音或障碍的地方。

2
我认为 Ewan 提出了一个很有意思的观点。以他的“子程序”为例,早期的编程语言中,向子程序传递参数并返回结果是必须显式编码的。而在现代语言中,这已经内置了。或者再举个例子:if/then/else 语句在大多数现代语言中都已内置。但在我还写汇编语言的时候,必须编写代码来完成这些操作。当然,并不需要写很多,但是你仍然必须实际编写跳转或goto语句绕过 else 块。而你必须自己编写这些东西意味着不同的程序员会以稍微不同的方式进行操作,而且总是有无穷无尽的诱惑去聪明地在这个程序中做一些稍微不同的事情,以使其更加高效或获得其他所谓的优势。
最近的例子是迭代器。在 C++ 和早期版本的 Java 中,你必须手动编写它们,但在 Java 5 中它们被内置了。这可以说是语法糖,你完全可以简单地创建迭代器函数。个人认为这是一个不错的特性。它是否能极大地提高我的生产力?不是的。
我们是否一直在做某些事情,但逻辑上应该将其内置到语言中以标准化和简化它?这是一个非常有趣的问题。我不认为任何人会认真地声称他们最喜欢的语言完美无缺,绝对没有任何改进的可能性。但下一个语言的方向将是什么呢?
显然,有些已添加到语言中的特性是无用的额外负担。在我谦虚的看法中,Java 枚举所做的远远超过了必要的范围,它们增加了很多无端的负担。我相信其他人会持不同意见,并说他们发现它们非常有用。
我没有结论。我只是同意这是一个令人着迷的问题。

我必须感谢链接文章提供的原始思想。你关于语法糖的观点让我想到了不同种类语言改进之间的区别。一方面,有些改进仅仅是使我们已经能够通过函数和类费力地组合起来的结构更容易创建。另一方面,真正杰出的创新,例如子程序或if-else块,在编程领域标志着根本性的转变。 - Ewan Todd
我有点不同意,因为我很难想到一个编程结构是无法通过足够的努力实现的。你可以编写子程序或if/else语句,或者在汇编语言中进行面向对象编程,只是比较困难。因此,这不是“可能但困难”与“不可能”的区别,而是“困难但实用”与“过于繁琐”的区别。但我认为这不是你的重点,而是你在谈论“可爱”和“聪明”的区别。对吗? - Jay

1

我认为有些设计模式确实代表了语言上的弱点,而新语言则将现有模式纳入一等公民。一个新语言采用其他语言已有的设计模式(如依赖注入、不可变性等)并将它们作为一流语言级别的特性整合进去的例子是 Google 的 NOOP


1

我在想一门语言能塞多少东西进去才不会变得太“庞大”。

我喜欢的编程语言足够小,可以一次性全部记住。DI等结构性问题是否应该成为语言的一部分?

开发人员实际上需要多少语言辅助呢?

对于代码合同(requires、ensures),如果它是语言的重要组成部分那当然很好,但并非必须如此。这仍然可以作为库的一部分。


1
可以提出一个论点,即语言应该尽可能小而正交,其库应该是有用的大型库。换句话说,尽可能将尽可能多的内容转移到库中,而不是用大量很少使用的奇特语法和特殊情况来混淆语言。 - David R Tribble
1
记忆一种更大的语言难还是记忆一种较小的语言及其额外的模式难? - David Thornley
将那些具有“通用应用”的核心元素放在语言中会更容易,而将那些需要在特定情况下使用的东西放入库中。您可以随时在参考资料中查找模式,但您在语言中需要的日常事物应该被记住。 - Robert Harvey
通常情况下,你可以在更小(但完整)的语言中更加高效地工作。 - Robert Harvey

0

每种语言都是一组任意的设计模式,其语法作为所选模式的符号表示。对于未选择的模式,您必须在语法的限制内进行干预以表达它们。 大多数语言不允许其语法过多地改变以同化更高级别的模式。

一个可以无限制地做到这一点的语言将是没有严格语法的语言(或者换句话说,允许无缝同化任何高级别模式的语言)。 请参见元语言抽象

我想到的是Scheme/Lisp。


0

设计模式并不是语言的弱点,它们提供了针对重复问题的设计解决方案。

随着时间的推移,许多事物都在不断发展,我认为企业集成模式将会变得流行。

如果不同的企业应用程序需要进行通信,这些模式提供了最佳解决方案。

  1. 集成风格文档介绍了应用程序集成的不同方式,提供了集成技术的历史记录。所有后续的模式都遵循消息传递风格。
  2. 通道模式描述了消息如何通过消息通道进行传输。这些模式由大多数商业和开源消息系统实现。
  3. 消息构建模式描述了跨消息系统传输的消息的意图、形式和内容。本节的基本模式是消息模式。
  4. 路由模式讨论了如何将消息从发送者路由到正确的接收者。消息路由模式从一个通道消耗一条消息,并根据一组条件将其重新发布到另一个通道,通常不进行修改。本节中介绍的模式是消息路由器模式的特化。
  5. 转换模式更改消息的内容,例如以适应发送和接收系统使用的不同数据格式。可能需要添加、删除数据或重新排列现有数据。本节的基本模式是消息翻译器。
  6. 端点模式描述了消息系统客户端如何生成或消费消息。
  7. 系统管理模式描述了保持复杂的基于消息的系统运行所需的工具,包括处理错误条件、性能瓶颈和参与系统的更改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接