自从我去年开始学习f#和OCaml以来,我已经阅读了大量的文章,这些文章坚持认为设计模式(尤其是Java中的)是命令式语言中缺失特性的变通方法。我发现的一篇文章给出了相当有力的主张:

Most people I've met have read the Design Patterns book by the Gang of Four (GoF). Any self respecting programmer will tell you that the book is language agnostic and the patterns apply to software engineering in general, regardless of which language you use. This is a noble claim. Unfortunately it is far removed from the truth. Functional languages are extremely expressive. In a functional language one does not need design patterns because the language is likely so high level, you end up programming in concepts that eliminate design patterns all together.

函数式编程(FP)的主要特性包括函数作为一类值、curry化、不可变值等。在我看来,OO设计模式是否接近这些特性并不明显。

此外,在支持OOP的函数式语言(如f#和OCaml)中,使用这些语言的程序员显然会使用与其他OOP语言相同的设计模式。事实上,现在我每天都在使用f#和OCaml,我在这些语言中使用的模式与我在Java中使用的模式之间没有明显的区别。

函数式编程消除了对面向对象设计模式的需求这一说法是否属实?如果是这样的话,你能发布或链接到一个典型的OOP设计模式的例子及其功能对等物吗?


当前回答

OOP和GoF模式处理状态。OOP对现实进行建模,使代码库尽可能接近现实的给定需求。GoF设计模式是为解决原子现实问题而确定的模式。它们以语义的方式处理状态问题。

因为在真正的函数式编程中不存在状态,所以应用GoF模式没有意义。功能设计模式与GoF设计模式是不同的。与现实相比,每个功能设计模式都是人为的,因为函数是数学的构造,而不是现实。

函数缺乏时间的概念,因为无论当前时间是多少,它们总是返回相同的值,除非时间是函数参数的一部分,这使得处理“未来的请求”非常困难。混合语言混合了这些概念,使得这些语言不是真正的函数式编程语言。

Functional languages are rising only because of one thing: the current natural restrictions of physics. Todays processors are limited in their speed of processing instructions due to physical laws. You see a stagnation in clock frequency but an expansion in processing cores. That's why parallelism of instructions becomes more and more important to increase speed of modern applications. As functional programming by definition has no state and therefore has no side effects it is safe to process functions safely in parallel.

GoF模式并没有过时。它们至少对真实世界的需求建模是必要的。但是如果你使用函数式编程语言,你必须将它们转换成它们的混合等价物。最后,如果使用持久性,就没有机会只编写函数式程序。对于程序的混合元素,仍然需要使用GoF模式。对于任何其他纯功能性的元素,没有必要使用GoF模式,因为没有状态。

因为GoF模式对于真正的函数式编程不是必需的,这并不意味着不应该应用SOLID原则。SOLID原则超越了任何语言范式。

其他回答

正如公认的答案所说,OOP和FP都有其特定的模式。

然而,有一些模式是非常常见的,我能想到的所有编程平台都应该有。以下是一个(不完整的)列表:

Adapter. I can hardly think of a useful programming platform which is so comprehensive (and self-fulfilled) that it does not need to talk to the world. If it is going to do so, an adapter is definitely needed. Façade. Any programming platforms that can handle big source code should be able to modularise. If you were to create a module for other parts of the program, you will want to hide the "dirty" parts of the code and give it a nice interface. Interpreter. In general, any program is just doing two things: parse input and print output. Mouse inputs need to be parsed, and window widgets need to be printed out. Therefore, having an embedded interpreter gives the program additional power to customise things.

另外,我注意到在典型的FP语言Haskell中,有一些类似于GoF模式的东西,但名称不同。在我看来,这表明它们存在,因为在FP和OOP语言中都有一些共同的问题需要解决。

单子转换器和装饰器。前者用于向现有的单子中添加额外的能力,后者用于向现有的对象中添加额外的能力。

函数式编程不能取代设计模式。设计模式是不可替代的。

模式就是存在的;它们是随着时间的推移而出现的。GoF的书将其中一些正规化了。如果随着开发人员使用函数式编程语言而出现新的模式,那将是令人兴奋的事情,也许也会有关于它们的书籍。

GoF这本书明确地将自己与面向对象绑定在一起——书名是《设计模式——可重用面向对象软件的元素》(重点是我的)。

恕我说一句,函数式编程最重要的特点是,你只用表达式来编程——表达式中的表达式,表达式中的表达式,所有的表达式都计算到最后,最终的表达式“计算时使机器变热”。

以我之见,面向对象编程的最重要的特征是,您正在使用具有内部状态的对象进行编程。在纯函数中不能有内部状态——面向对象的编程语言需要语句来实现。(函数式编程中没有语句。)

你是在拿苹果和橘子作比较。面向对象编程的模式不适用于函数编程,因为函数式编程是使用表达式进行编程,而面向对象编程是使用内部状态进行编程。

甚至OO设计模式解决方案也是特定于语言的。

设计模式是编程语言无法解决的常见问题的解决方案。在Java中,单例模式解决单一的(简化的)问题。

在Scala中,除了Class,还有一个顶级的构造,叫做Object。它是惰性实例化的,只有一个。你不必使用单例模式来获得一个单例。这是语言的一部分。