自从我去年开始学习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和FP有不同的目标。OOP旨在封装软件组件的复杂/可移动部分,FP旨在最小化软件组件的复杂性和依赖性。

然而,这两种范式并不一定是100%矛盾的,可以一起应用,从两个世界中获得好处。

即使使用像c#这样原生不支持函数式编程的语言,如果您理解FP原则,您也可以编写函数式代码。同样地,如果你理解OOP原则、模式和最佳实践,你也可以使用f#应用OOP原则。无论您使用何种编程语言,您都可以根据您试图解决的情况和问题做出正确的选择。

其他回答

我想引用Jeremy Gibbons的两篇优秀但有些密集的论文:《作为高阶数据类型泛型程序的设计模式》和《迭代器模式的精髓》(这两篇文章都可以在http://www.comlab.ox.ac.uk/jeremy.gibbons/publications/上找到)。

它们都描述了惯用函数构造如何覆盖其他(面向对象)设置中特定设计模式所覆盖的领域。

Norvig的演示暗示了他们对所有GoF模式的分析,他们说23个模式中有16个在函数式语言中有更简单的实现,或者只是语言的一部分。因此,大概至少有7个要么是a)同样复杂,要么是b)没有出现在语言中。不幸的是,我们没有列举它们!

我认为很明显,GoF中的大多数“创造性”或“结构性”模式只是让Java或c++中的原始类型系统做你想做的事情的技巧。但是不管你用什么语言编程,其余的都是值得考虑的。

一个可能是Prototype;虽然它是JavaScript的基本概念,但它必须在其他语言中从头开始实现。

我最喜欢的模式之一是空对象模式:表示一个对象不做任何适当的事情。这可能更容易在函数式语言中建模。然而,真正的成就是视角的转变。

这是另一个讨论这个话题的链接:http://blog.ezyang.com/2010/05/design-patterns-in-haskel/

在他的博客文章中,Edward用Haskell描述了所有23种原始的GoF模式。

GoF设计模式是为Simula 67的后代面向对象语言(如Java和c++)编写的变通方法。

设计模式处理的大多数“弊病”是由以下原因引起的:

statically typed classes, which specify objects, but are not themselves objects; restriction to single dispatch (only the leftmost argument is used to select a method, the remaining arguments are considered as static types only: if they have dynamic types, it's up to the method to sort that out with ad-hoc approaches); distinction between regular function calls and object-oriented function calls, meaning that object-oriented functions cannot be passed as functional arguments where regular functions are expected and vice versa; and distinction between "base types" and "class types".

在通用Lisp对象系统中,这些设计模式中没有一个不会消失,即使解决方案的结构本质上与相应的设计模式相同。(此外,该对象系统比GoF书早了十多年。Common Lisp在该书第一次出版的同一年成为了ANSI标准。)

就函数式编程而言,模式是否适用于它取决于给定的函数式编程语言是否具有某种对象系统,以及它是否模仿受益于模式的对象系统。这种类型的面向对象不能很好地与函数式编程相结合,因为状态的突变是最重要的。

构造和非突变访问与函数式编程兼容,因此与抽象访问或构造有关的模式可以适用:像工厂、Facade、代理、Decorator和访问者这样的模式。

另一方面,像状态和策略这样的行为模式可能不能直接应用于功能性OOP,因为状态突变是它们的核心。这并不意味着它们不适用;也许它们以某种方式与任何可用于模拟可变状态的技巧结合应用。

模式是解决类似问题的方法,这些问题会一次又一次地出现,然后被描述和记录。所以不,FP不会取代模式;然而,FP可能会创建新的模式,并使一些当前的“最佳实践”模式“过时”。