自从我去年开始学习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设计模式的例子及其功能对等物吗?


当前回答

在2013年的新书《函数式编程模式- In Scala and Clojure》中,作者Michael.B。Linn在很多情况下对GoF模式进行了比较和替换,并讨论了较新的功能模式,如“尾递归”、“记忆化”、“惰性序列”等。

这本书在亚马逊上有售。作为一个拥有几十年OO背景的人,我发现这本书内容丰富,令人鼓舞。

其他回答

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

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

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

函数式编程消除了对面向对象设计模式的需求这一说法是否属实?

函数式编程与面向对象编程不同。面向对象的设计模式不适用于函数式编程。取而代之的是函数式编程设计模式。

对于函数式编程,您不需要阅读面向对象设计模式书籍;你会读到其他关于FP设计模式的书籍。

语言无关的

不完全。对于面向对象语言,只有语言不可知。这种设计模式根本不适用于过程式语言。它们在关系数据库设计上下文中几乎没有意义。它们不适用于设计电子表格。

一个典型的OOP设计模式和它的功能对等物?

上述情况不应该存在。这就像要求将一段过程代码重写为OO代码。嗯……如果我将原始的Fortran(或C)翻译成Java,我所做的只是翻译它。如果我完全将其重写为面向对象范式,它将不再看起来像原始的Fortran或C语言——它将无法识别。

从面向对象设计到功能设计没有简单的映射。他们看问题的方式完全不同。

函数式编程(像所有编程风格一样)具有设计模式。关系数据库有设计模式,OO有设计模式,过程式编程有设计模式。任何事物都有设计模式,甚至是建筑物的结构。

设计模式——作为一个概念——是一种永恒的构建方式,与技术或问题领域无关。但是,特定的设计模式适用于特定的问题领域和技术。

每个人只要仔细思考自己在做什么,就会发现设计模式。

当你试着从“设计模式”(一般)和“FP vs . OOP”的层面来看待这个问题时,你会发现答案最多是模糊的。

但是,在这两个轴上深入研究,并考虑特定的设计模式和特定的语言功能,事情就会变得更清楚。

因此,例如,当使用具有代数数据类型和模式匹配、闭包、第一类函数等的语言时,一些特定的模式(如访问者、策略、命令和观察者)肯定会改变或消失。不过,GoF书中的其他一些模式仍然“存在”。

总的来说,我会说,随着时间的推移,特定的模式正在被新的(或正在流行的)语言特性所淘汰。这是语言设计的自然过程;随着语言变得越来越高级,以前只能在书中使用示例来调用的抽象现在成为特定语言特性或库的应用程序。

(顺便说一句:这是我最近写的一篇博客,上面有更多关于FP和设计模式讨论的链接。)

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可能会创建新的模式,并使一些当前的“最佳实践”模式“过时”。