函数式编程取代了GoF的devise模式吗?

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

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

function语言是非常有performance力的。 在一种function语言中,由于语言可能如此之高,所以不需要devise模式,最终可以将概念中的devise模式排除在外。

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

此外,在支持OOP的函数式语言(如F#和OCaml)中,使用这些语言的程序员使用与其他所有OOP语言相同的devise模式似乎是显而易见的。 实际上,现在我每天都在使用F#和OCaml,而且我在这些语言中使用的模式与我在使用Java编写时使用的模式之间没有明显的区别。

function性编程是否消除了对OOPdevise模式的需求,是否有任何事实? 如果是这样,你可以发布或链接到一个典型的OOPdevise模式的例子和它的function等效?

你引用的博客文章夸大了它的要求。 FP并不排除对devise模式的需求。 “devise模式”一词在FP语言中并没有被广泛用来描述相同的事物。 但它们存在。 函数式语言有很多最佳实践规则,forms为“当遇到问题X时,使用看起来像Y的代码”,这基本上是一种devise模式。

但是,大多数OOP特定的devise模式在function语言中几乎是不相干的,这是正确的。

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

以下是“四人帮”对这个问题的看法:

编程语言的select是重要的,因为它影响了一个人的观点。 我们的模式假定了Smalltalk / C ++级的语言特性,而这个select决定了什么可以轻松实现。 如果我们采用程序语言,我们可能会包含名为“inheritance”,“封装”和“多态性”的devise模式。 类似地,我们的一些模式直接由不太常见的面向对象的语言来支持。 例如,CLOS具有多种方法,从而减less了访问者等模式的需求。 事实上,Smalltalk和C ++之间有足够的差别,意味着某种模式可以用一种语言比另一种更容易expression。 (例如参见迭代器。)

(以上是引用“devise模式”一书的第4页第3段)

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

什么是命令模式,如果不是一级函数的近似值? :)在FP语言中,只需将一个函数作为parameter passing给另一个函数即可。 在一个OOP语言中,你必须把这个函数包装在一个类中,你可以实例化这个类,然后把这个对象传递给另一个函数。 效果是一样的,但是在OOP中它被称为devise模式,并且需要更多的代码。 抽象的工厂模式是什么,如果不是咖啡? 将参数一次传递给一个函数,来configuration当你最终调用它时吐出的数值。

所以是的,一些GoFdevise模式在FP语言中是冗余的,因为存在更强大和更易于使用的替代scheme。

但是当然还有devise模式,这些模式在FP语言中没有解决。 什么是单身人士的FP等值? (无视片刻,单身人士通常是一个可怕的模式使用)

而且它也是有效的。 正如我所说,FP也有其devise模式,人们通常不会这样想。

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

我们不需要devise模式来“增加一个静态variables”,或者“从该套接字读取”,因为这正是你所做的

在(纯)function语言中,副作用和可变状态是不可能的,除非你用monad“devise模式”或任何其他允许相同的方法来解决它。

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

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

但另一种可能性可能是你没有意识到你正在解决的问题,这将需要OOP语言的devise模式。

当你使用currying或者把一个函数作为一个parameter passing给另一个时,停下来想想如何用OOP语言来做这件事。

function性编程是否消除了对OOPdevise模式的需求,是否有任何事实?

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

无论如何,您可能会发现尝试使用“更清晰”的FP语言,比如ML(我个人最喜欢的,至less是为了学习的目的),或者Haskell,当你的时候没有OOP拐杖面对新的东西。


正如所料,有一些人反对我的devise模式的定义是“修补语言中的缺点”,所以这是我的理由:正如已经说过的,大多数devise模式都是特定于一种编程范式,有时甚至是一种特定的语言。 他们经常解决只存在于这种范式中的问题(请参阅FP的单子机,OOP的抽象工厂)。 FP为什么不存在抽象工厂模式? 因为它试图解决的问题在那里不存在。 所以,如果OOP语言中存在一个在FP语言中不存在的问题,那么显然这是OOP语言的一个缺点。 问题可以解决,但你的语言不这样做,但需要从你的一堆样板代码来解决它。 理想情况下,我们希望我们的编程语言神奇地让所有的问题消失。 任何仍然存在的问题原则上都是语言的缺点。 ;)

function性编程是否消除了对OOPdevise模式的需求,是否有任何事实?

函数式编程与面向对象编程不一样。 面向对象的devise模式不适用于函数式编程。 相反,你有function性的编程devise模式。

对于函数式编程,您将不会阅读面向对象的devise模式书籍,您将阅读关于FPdevise模式的其他书籍。

语言不可知的

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

典型的面向对象devise模式及其function等价物?

以上不应该存在。 这就像是要求将一段程序代码重写为OO代码。 呃…如果我把原来的Fortran(或者C)翻译成Java,那么除了翻译它之外我什么也没有做过。 如果我把它完全改写成面向对象(OO)范式,它将不再像原来的Fortran或C那样 – 它将无法辨认。

从面向对象devise到functiondevise没有简单的映射。 他们是非常不同的方式来看问题。

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

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

每个想到自己在做什么的人都会发现devise模式。

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

这个讨论的缺失部分是成语的概念。 Coplien的书“Advanced C ++”在这里影响巨大。 早在他发现克里斯托弗·亚历山大(Christopher Alexander)和“ 无名的专栏”之前,他还没有阅读亚历山大也谈不上明智的模式,他谈到掌握成语在真正学习语言方面的重要性。 他用C中的string复制为例,while(* from ++ = * to ++); 你可以看到这是一个缺less语言特征(或图书馆特征)的绷带,但真正重要的是它是一个比任何部分都更大的思想或expression单位。

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

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

GOF书明确地将自己与OOP联系在一起 – 标题是devise模式 – 可重用面向对象软件的元素(重点是我的)。

dynamic规划中的devise模式 Peter Norvig对这个总体主题进行了深思熟虑,但关于“dynamic”语言而不是“function”(有重叠)。

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

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

当你试图从“devise模式”(一般来说)和“FP与OOP”的层面来看待这个问题时,你会发现最好的答案是模糊的。

不过,要在两个轴上更深层次地考虑具体的devise模式具体的语言特征 ,事情就会变得更加清晰。

因此,例如,当使用具有代数数据types和模式匹配闭包头等function等的语言时, 访问者策略命令观察者等特定模式肯定会改变或消失。来自GoF书籍的一些其他模式仍然但是“坚持”。

总的来说,随着时间的推移,我会说特定的模式正在被新的(或只是stream行的)语言特征所消除。 这是语言devise的自然过程; 随着语言越来越高级化,以前只能在使用示例的书中才能提出的抽象现在成为特定语言特征或库的应用。

(另外:这是我写的一个最近的博客 ,有更多关于FP和devise模式讨论的链接。)

Norvig的演示暗示了他们对所有GoF模式的分析,他们说23种模式中的16种在函数式语言中有更简单的实现,或者仅仅是语言的一部分。 所以大概他们中至less有七个或者是a)同样复杂或者b)不存在于语言中。 对我们不幸的是,他们没有列举!

我认为很明显的是,GoF中的大部分“创build”或“结构”模式仅仅是获取Java或C ++中的原始types系统来做你想做的事情的技巧。 但是不pipe你用什么语言编程,其余的都值得考虑。

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

我最喜欢的模式之一是空对象模式:表示没有东西作为一个适当的没有什么东西的对象。 这在function语言中可能更容易build模。 然而,真正的成就是视angular的转变。

我会说,当你有像Lisp这样的语言支持macros,那么你可以build立自己的领域特定的抽象,抽象往往比一般的成语解决scheme好得多。

甚至OOdevise模式解决scheme都是特定于语言的。 devise模式是您的编程语言无法为您解决的常见问题的解决scheme。 在Java中,Singleton模式解决了一些(简化的)问题。 在Scala中,除了Class之外,还有一个名为Object的顶级构造。 这是懒惰地实例化,只有一个。 你不必使用Singleton模式来获得Singleton。 这是语言的一部分。

模式是解决类似问题的方法,一次又一次地看到,然后得到描述和logging。 所以不,FP不会取代模式; 然而,计划生育可能会创造新的模式,并使一些当前的“最佳实践”模式“过时”。

正如其他人所说,function编程有特定的模式。 我认为摆脱devise模式的问题不是转换到function性问题,而是语言function的问题

看看Scala如何消除“单例模式”:只需声明一个对象而不是类。 另一个function,模式匹配,有助于避免访客模式的混乱。 在这里看比较: http : //andymaleh.blogspot.com/2008/04/scalas-pattern-matching-visitor-pattern.html

和F#一样,Scala是OOfunction的融合。 我不知道F#,但它可能有这种function。

闭包以function语言存在,但不限于此。 他们帮助与委托人模式。

还有一个观察。 这段代码实现了一个模式:它是如此的经典,它是如此的元素,我们通常不认为它是一个“模式”,但它肯定是:

 for(int i = 0; i < myList.size(); i++) { doWhatever(myList.get(i)); } 

像Java和C#这样的命令式语言已经采用了本质上是一个function性的构造来处理这个问题:“foreach”。

GoF Design Patterns为Simula 67的后代OO语言编写了解决方法,例如Java和C ++。

devise模式处理的大部分“瑕疵”都是由以下原因造成的:

  • 静态types的类,它们指定对象,但不是它们自己的对象;
  • (只有最左边的参数被用来select一个方法,其余的参数只被认为是静态types:如果他们有dynamictypes,则由特殊方法来分类)。
  • 常规函数调用和面向对象函数调用之间的区别,这意味着面向对象的函数不能作为预期常规函数的函数parameter passing,反之亦然; 和
  • “基本types”和“class级types”之间的区别。

这些devise模式中没有一个在Common Lisp对象系统中不会消失,即使解决scheme的构造方式与对应的devise模式基本相同。 (而且,这个目标系统在十年前已经成为GoF的书,在这本书首次出版的同一年,Common Lisp就成为了ANSI标准。

就函数式编程而言,这些模式是否适用于其中,取决于给定的函数式编程语言是否具有某种对象系统,以及是否在受益于模式的对象系统之后进行build模。 这种types的面向对象不能很好地与函数式编程相结合,因为状态的变化处于前面和中心。

构造和非变异访问与函数式编程兼容,因此与抽象访问或构造相关的模式可以适用:工厂,门面,代理,装饰器,访问者等模式。

另一方面,像State和Strategy这样的行为模式可能不直接应用于functionOOP,因为状态的变化是其核心。 这并不意味着他们不适用; 也许他们以某种方式结合使用任何可用于模拟可变状态的技巧。

我想插入一些由Jeremy Gibbons撰写的优秀但很密集的论文:“devise模式作为高阶数据types – 通用程序”和“迭代器模式的本质”(可以在这里find: http:// www。 comlab.ox.ac.uk/jeremy.gibbons/publications/ )。

这些都描述了惯用function结构如何覆盖其他(面向对象)设置中特定devise模式所覆盖的地形。

没有提出types系统,你就不能进行这个讨论。

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

那是因为这些function不能解决OOP所做的相同的问题…它们是命令式编程的替代scheme。 OOP的FP答案在于ML和Haskell的types系统…特别是总和types,抽象数据types,ML模块,Haskelltypes类。

但是当然还有devise模式,这些模式还没有被FP语言所解决。 什么是单身人士的FP等值? (无视片刻,单身人士通常是一个可怕的模式使用)

typeclasses做的第一件事是消除单身的需要。

你可以通过23清单,消除更多,但我没有时间现在。

我认为只有两个GoFdevise模式被devise为将函数式编程逻辑引入到自然OO语言中。 我想到战略与指挥。 一些其他GoFdevise模式可以通过function编程进行修改,以简化devise并保持目的。

OOP和GoF模式处理国家。 面向对象模型的现实,使代码基地尽可能接近现实的要求。 GoFdevise模式是为解决primefaces现实世界问题而确定的模式。 他们以语义的方式处理国家的问题。

在实际的函数式编程中,不存在任何状态,应用GoF模式是没有意义的。 没有像GoFdevise模式一样的functiondevise模式。 每个functiondevise模式都是人造的,与现实相反,因为function是math而不是现实的结构。

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

function语言的兴起只是因为一件事情:物理学当前的自然限制。 由于物理规律,今天处理器的处理速度有限。 你看到时钟频率停滞不前,但处理内核的扩展。 这就是为什么指令的并行性对于提高现代应用程序的速度变得越来越重要。 由于按照定义的function编程没有状态,因此没有副作用,所以安全地并行处理function是安全的。

GoF模式不是过时的。 他们至less需要模拟真实世界的需求。 但是如果你使用一种function性的编程语言,你必须把它们转换成混合的等价物。 最后,如果你使用持久化,你就没有机会只做function程序。 对于您的程序的混合元素,仍然有必要使用GoF模式。 任何其他纯粹function的元素都没有必要使用GoF模式,因为没有状态。

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

函数式编程不会取代devise模式。 devise模式不能被取代。

模式简单地存在; 他们随着时间而出现。 GoF书正式化了其中的一些。 如果开发人员使用function强大的编程语言,新的模式变得更加激动人心,那么也许还会出现一些关于它们的书籍。

基本上, 是的

  • 当一个模式绕开缺less的function(高阶函数,stream处理…), ultimalty促进组成 。
  • 一次又一次地重新编写模式实现的需求本身可以被看作是一种语言嗅觉 。

此外,如果你愿意挖掘,这个页面(AreDesignPatternsMissingLanguageFeatures)提供了一个“模式/特征”翻译表和一些很好的讨论。

在2013年的新书“function编程模式 – 斯卡拉和Clojure”作者Michael.B。 在很多情况下,Linn做了一个体面的工作来比较和提供GoF模式的replace,还讨论了诸如“尾recursion”,“记忆”,“懒序列”等更新的function模式。

这本书在亚马逊上可用。 从几十年的OO背景中发现,我发现它非常丰富和令人鼓舞。

我认为每个范式都有不同的目的,因此不能用这种方式来比较。

我还没有听说过GoF的devise模式适用于所有的语言。 我听说它们适用于所有的OOP语言 。 如果你使用函数式编程,那么你解决的问题的领域就不同于OO语言。

我不会使用函数式语言来编写用户界面,但是像C#或Java这样的面向对象语言之一会使这个工作变得更容易。 如果我正在编写一个函数式语言,那么我不会考虑使用面向对象的devise模式。

OOP和FP有不同的目标,OOP旨在封装软件组件的复杂性/移动部分,而FP旨在最大限度地减less软件组件的复杂性和依赖性,但是这两种范例不一定是100%矛盾的,可以一起使用以获得收益来自两个世界。 即使使用的语言本身不支持C#等函数式编程,如果您了解FP原则,也可以编写function代码,如果您了解OOP原则,模式和最佳实践,也可以使用F#应用OOP原则。 无论您使用哪种编程语言,您都可以根据您尝试解决的情况和问题做出正确的select。

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

但是,有一些这样的模式非常普遍,所有我能想到的编程平台都应该有。 这是一个(不完整)清单:

  • 适配器。 我很难想象一个如此全面(自我实现)的有用的编程平台,它不需要和世界交stream。 如果打算这样做,一个适配器是绝对需要的。

  • 正面。 任何可以处理大型源代码的编程平台都应该能够模块化。 如果您要为程序的其他部分创build一个模块,您将需要隐藏代码的“脏”部分,并给它一个很好的界面。

  • 解释。 一般来说,任何程序只是做两件事:parsinginput和打印输出。 鼠标input需要被parsing,窗口小部件需要打印出来。 因此,有一个embedded式解释器给程序额外的权力来定制的东西。

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

  • Monad变压器和装饰者。 前者用于向现有的monad添加额外的能力,后者则为现有的对象添加额外的能力。