函数式编程是否取代GoF设计模式?

自从去年我开始学习F#和OCaml以来,我已经阅读了大量的文章,坚持认为设计模式(特别是Java)是命令式语言中缺失功能的解决方法。 我发现的一篇文章提出了相当强烈的说法:

我遇到的大多数人都阅读了四人帮的设计模式书。 任何自我尊重的程序员都会告诉你,这本书是语言不可知的,而且这些模式一般适用于软件工程,无论你使用哪种语言。 这是一个崇高的主张。 不幸的是,它远离事实。

功能语言非常有表现力。 在一种功能语言中,不需要设计模式,因为语言可能如此之高,所以最终编程的概念将所有设计模式都排除在外。

函数式编程的主要特征包括函数作为第一类值,currying,不可变值等等。对我来说,OO设计模式近似于任何这些特性似乎并不明显。

另外,在支持OOP的函数式语言(如F#和OCaml)中,使用这些语言的程序员使用与其他所有OOP语言相同的设计模式似乎很明显。 事实上,现在我每天都在使用F#和OCaml,而且我在这些语言中使用的模式与我在使用Java编写时使用的模式之间没有明显的差异。

功能性编程消除了对OOP设计模式的需求的说法有没有道理? 如果是这样,你可以发布或链接到一个典型的OOP设计模式及其功能等效的例子吗?


你引用的博客文章夸大了它的说法。 FP并没有消除对设计模式的需求。 “设计模式”这个术语并没有广泛用于描述FP语言中的相同事物。 但它们存在。 函数式语言有很多“当遇到问题X,使用看起来像Y的代码”形式的最佳实践规则,这基本上就是设计模式。

但是,大多数OOP特定的设计模式在函数式语言中几乎无关紧要。

我认为这不应该是特别有争议的,一般说来,设计模式只是为了弥补语言中的缺陷。 如果另一种语言可以轻易解决同样的问题,那么其他语言就不需要它的设计模式。 这种语言的用户可能甚至不知道问题存在,因为这不是该语言的问题。

以下是四人帮对这个问题所说的话:

编程语言的选择很重要,因为它影响了一个人的观点。 我们的模式假定了Smalltalk / C ++级别的语言特性,并且该选择决定了什么可以轻松实现,哪些不能轻松实现。 如果我们采用程序语言,我们可能会包含名为“继承”,“封装”和“多态性”的设计模式。 同样,我们的一些模式直接由不太常见的面向对象语言来支持。 例如,CLOS具有多种方法,可以减少对Visitor等模式的需求。 实际上,Smalltalk和C ++之间有足够的差别,意味着某种模式可以用一种语言比另一种更容易表达。 (例如参见迭代器。)

(以上是“设计模式简介”一书的第4页第3段)

函数式编程的主要特征包括函数作为第一类值,currying,不可变值等等。对我来说,OO设计模式近似于任何这些特性似乎并不明显。

什么是命令模式,如果不是一流功能的近似值? :)在FP语言中,您只需将一个函数作为参数传递给另一个函数。 在一个OOP语言中,你必须把这个函数包装到一个类中,你可以实例化这个类,然后把这个对象传递给另一个函数。 效果是一样的,但是在OOP中它被称为设计模式,并且需要更多的代码。 什么是抽象工厂模式,如果不是卷曲的? 每次将参数传递给一个函数,以便配置最终调用它时吐出的什么类型的值。

所以,有些GoF设计模式在FP语言中是冗余的,因为存在更强大和更易于使用的替代方案。

但是当然还有一些设计模式并没有被FP语言所解决。 什么是单身人士的FP等值? (忽略单身人士通常使用的可怕模式)

它也适用于两种方式。 正如我所说的,FP也有其设计模式,人们通常不会认为它们是这样的。

但是你可能碰到过单子。 他们是什么,如果不是“处理全球国家”的设计模式? 这是一个在OOP语言中如此简单的问题,因此在那里不存在等效的设计模式。

我们不需要“增加静态变量”或“从该套接字读取”的设计模式,因为这正是您所做的。

在(纯粹的)函数式语言中,除非用monad“设计模式”或任何其他允许相同事物的方法解决它,否则副作用和可变状态是不可能的。

另外,在支持OOP的函数式语言(如F#和OCaml)中,使用这些语言的程序员使用与其他所有OOP语言相同的设计模式似乎很明显。 实际上,现在我每天都使用F#和OCaml,并且在我使用这些语言的模式与我在使用Java编写时使用的模式之间没有明显的差异。

也许是因为你仍然在想方设法? 很多人在他们一生中处理命令式语言之后,在尝试使用功能性语言时很难放弃这种习惯。 (我在F#上看到过一些非常有趣的尝试,其中每一个函数都只是一串'let'语句,基本上就好像你采用了C程序,并用'let'替换了所有分号:))

但是另一种可能性可能是,你只是没有意识到你正在解决的问题微不足道,这需要使用OOP语言的设计模式。

当你使用currying或者将一个函数作为参数传递给另一个时,停下来想想你会如何在OOP语言中做到这一点。

功能性编程消除了对OOP设计模式的需求的说法有没有道理?

是的。 :)当您使用FP语言工作时,不再需要特定于OOP的设计模式。 但是你仍然需要一些通用的设计模式,比如MVC或者其他非OOP特定的东西,而你需要一些新的FP特定的“设计模式”。 所有语言都有它们的缺点,而设计模式通常是我们如何解决它们的方法。

无论如何,您可能会发现尝试使用“更清晰”的FP语言(例如ML(我个人最喜欢的,至少用于学习目的))或Haskell,在您没有OOP拐杖时,面对新的事物。


正如所料,少数人反对将我的设计模式定义为“修补语言中的缺点”,所以这就是我的理由:如前所述,大多数设计模式都是针对一种编程模式,或者有时甚至是一种特定语言。 通常,他们解决只存在于该范式中的问题(请参阅FP的monads,或面向OOP的抽象工厂)。 FP为什么不存在抽象工厂模式? 因为它试图解决的问题在那里不存在。 所以,如果在OOP语言中存在一个在FP语言中不存在的问题,那么显然这是OOP语言的一个缺点。 这个问题可以解决,但是你的语言并没有这样做,但需要大量的样板代码来解决它。 理想情况下,我们希望我们的编程语言神奇地让所有问题消失。 任何仍然存在的问题原则上都是语言的缺点。 ;)


功能性编程消除了对OOP设计模式的需求的说法有没有道理?

函数式编程与面向对象编程不同。 面向对象的设计模式不适用于函数式编程。 相反,你有功能性的编程设计模式。

对于函数式编程,您不会阅读面向对象的设计模式书,您可以阅读关于FP设计模式的其他书籍。

语言不可知的

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

典型的面向对象设计模式及其功能等价物?

以上不应该存在。 这就像要求将一段程序代码重写为OO代码。 嗯......如果我将原来的Fortran(或C)翻译成Java,那么除了翻译它之外,我没有做过任何其他的事情。 如果我将它完全重写为面向对象的范例,它将不再像原来的Fortran或C那样 - 它将无法识别。

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

函数式编程(如所有编程风格)都有设计模式。 关系数据库具有设计模式,OO具有设计模式,程序编程具有设计模式。 一切都有设计模式,甚至建筑的建筑。

设计模式 - 作为一个概念 - 是一种永恒的建设方式,无论技术或问题领域如何。 但是,具体的设计模式适用于特定的问题领域和技术。

每个想到他们在做什么的人都会发现设计模式。


布赖恩关于语言和模式之间紧密联系的评论是关键的,

这个讨论的缺失部分是成语的概念。 Coplien的书“Advanced C ++”在这里影响巨大。 很久之前,他发现克里斯托弗亚历山大和无名的专栏(并且你不能在没有阅读亚历山大的情况下理智地谈论模式),他谈到掌握成语在真正学习语言方面的重要性。 他以C中的字符串副本为例,while(* from ++ = * to ++); 你可以把它看作是缺少语言特征(或图书馆特征)的一种绷带,但真正重要的是它是一个比它的任何部分都更大的思想或表达单位。

这就是模式和语言正在试图做的事情,以便我们更简洁地表达我们的意图。 思想单位越丰富,你可以表达的想法越复杂。 在一系列规模上从丰富的共享词汇 - 从系统架构到有点混搭 - 让我们能够进行更加智能的对话,并思考我们应该做什么。

我们也可以作为个人学习。 这是练习的全部要点。 我们每个人都能理解和使用我们永远无法想象的事情。 语言,框架,图书馆,模式,成语等都有其共享知识财富的地方。

链接地址: http://www.djcxy.com/p/7419.html

上一篇: Does functional programming replace GoF design patterns?

下一篇: What is the idiomatic Go equivalent of C's ternary operator?