问题描述
自从我开始学习 f#和 ocaml 去年,我已经阅读了大量文章,这些文章坚持认为设计模式(尤其是在Java中)是缺少功能的方法在命令式语言中.我找到了一篇文章提出了相当强烈的主张:
我遇到的大多数人都读过 设计模式书 四个(GOF).任何自我尊重的程序员 会告诉你这本书是 语言不可知论和模式 申请软件工程 一般,无论哪种语言 你用.这是一个崇高的主张. 不幸的是它与 真相.
功能性语言极为 表现力. 在功能语言中 一个不需要设计模式 因为语言可能很高 级别,您最终会编程 消除设计的概念 图案一起.
功能编程(FP)的主要特征包括功能作为头等价值,咖喱,不变的值等.对我来说,OO设计模式近似于这些功能,这似乎并不明显.
.此外,在支持OOP的功能语言中(例如F#和OCAML),对我来说,使用这些语言的程序员将使用与其他所有OOP语言可用的相同设计模式.实际上,现在我每天都使用f#和ocaml,在这些语言中使用的模式与我在Java中使用时使用的模式之间没有明显的区别.
功能编程消除了对OOP设计模式的需求的说法有什么事实吗?如果是这样,您可以发布或链接到典型的OOP设计模式及其功能等效的示例吗?
推荐答案
您引用的博客文章夸大了其主张. FP不会消除设计模式的需求.术语"设计模式"并未广泛用来用FP语言描述同一件事.但是它们存在.功能性语言具有大量的最佳实践规则:"当您遇到问题X时,使用看起来像Y的代码",这基本上是设计模式.
但是,大多数特定于OOP的设计模式与功能性语言无关.
是正确的.我认为,说设计模式一般而言仅存在以修补语言中的缺点,这不是特别有争议的. 而且,如果另一种语言能够琐碎地解决相同的问题,那么其他语言将不需要设计模式.该语言的用户甚至可能不知道问题存在,因为,这不是该语言的问题.
这是四个团伙对此问题的说法:
编程语言的选择很重要,因为它会影响人们的观点.我们的模式假设SmallTalk/C ++ - 级别的语言功能,该选择决定了可以轻松实现的方法.如果我们假设程序语言,我们可能会包括称为"继承","封装"和"多态性"的设计模式.同样,我们的某些模式直接由不太常见的面向对象的语言支持.例如,关闭的多方法可以减少对访问者之类的模式的需求.实际上,SmallTalk和C ++之间存在足够的差异,意味着某些模式可以比另一种语言更容易表达. (例如,请参见迭代器.)
(以上是设计模式书籍的引用,第4页,第3段)
功能的主要特征 编程包括 一流的值,咖喱, 不变的价值等似乎没有 对我来说,OO设计模式很明显 正在近似这些 功能.
如果不是一流函数的近似,命令模式是什么? :) 在FP语言中,您只需将函数作为参数传递给另一个函数. 在OOP语言中,您必须在类中包裹该功能,您可以实例化,然后将该对象传递给另一个函数.效果是相同的,但是在OOP中,它称为设计模式,并且需要更多的代码. 如果不咖喱,抽象的工厂模式是什么?一次将参数传递到一个函数,以配置最终调用它时吐出的值.
是的,几种GOF设计模式在FP语言中呈现多余,因为存在更强大且易于使用的替代方案.
当然,仍然有一些设计模式,这些模式不是通过FP语言解决的 .单身人士的FP等效是什么? (一会儿忽略单身通常是可怕的模式.)
它也可以双向工作.正如我所说,FP也具有其设计模式.人们通常不这样认为它们.
但是您可能已经跨过单子.如果不是"处理全球国家"的设计模式,它们是什么?这是一个非常简单的OOP语言,没有等效的设计模式.
我们不需要"递增静态变量"或"从该套接字读取"的设计模式,因为这只是您的 do ..
说单调是一种设计模式,就像说具有通常操作的整数一样荒谬,而零元素是一种设计模式.不,单子是数学模式,而不是设计模式.
在(纯)功能性语言,副作用和可变状态是不可能的,除非您使用单月的"设计模式"或任何其他允许同一件事的方法来处理它.
此外,用功能语言 支持OOP(例如F#和 OCAML),对我来说似乎很明显 使用这些语言的程序员 将使用相同的设计模式 发现其他所有OOP 语.实际上,现在我使用F# 和Ocaml每天都没有 在 我在这些语言中使用的模式与 我写入时使用的图案 Java.
也许是因为您仍在思考?许多人在处理命令式语言一生之后,当他们尝试一种功能性语言时,很难放弃这种习惯. (我在F#上看到了一些非常有趣的尝试,其中每个每个函数只是" Let"陈述的一串,基本上就像您采用了C程序一样,并用'代替了所有半olons'让'.:))
,但另一种可能性可能是您还没有意识到您正在琐碎地解决问题,这需要用OOP语言进行设计模式.
当您使用咖喱或将函数作为参数传递给他人时,请停下来思考一下您如何用OOP语言做到这一点.
有什么真相的说法 功能编程消除了 需要OOP设计模式?
是的. :) 当您使用FP语言工作时,您将不再需要特定于OOP的设计模式.但是,您仍然需要一些一般的设计模式,例如MVC或其他非木板特定内容,并且需要一些新的FP特定的"设计模式".所有语言都有其缺点,设计模式通常是我们围绕它们的工作方式.
无论如何,您可能会发现有趣的是在"清洁器" FP语言上尝试您的手,例如 ml (至少是出于学习目的,我个人最喜欢的)或
正如已经说过的,大多数设计模式都针对一种编程范式,甚至是一种特定语言.通常,它们解决了该范式中仅存在的问题(请参阅FP或OOP的抽象工厂). 为什么FP中不存在抽象工厂模式?因为它试图解决的问题不存在. 因此,如果以FP语言不存在的OOP语言存在问题,那么显然这是OOP语言的缺点.可以解决这个问题,但是您的语言不这样做,但是需要您的一堆样板代码才能围绕它工作.理想情况下,我们希望我们的编程语言神奇地使所有问题都消失了.任何仍然存在的问题原则上都是语言的缺点. ;) 声称功能编程消除了对OOP设计模式的需求吗? 功能编程与面向对象的编程不同.面向对象的设计模式不适用于功能编程.相反,您有功能编程设计模式. 对于功能编程,您不会阅读OO设计图案书;您将阅读有关FP设计模式的其他书籍. 语言不可知论 不是完全.只有关于OO语言的语言敏捷.设计模式根本不适用于程序语言.它们在关系数据库其他推荐答案
典型的OOP设计模式及其功能等效?
以上不应该存在.这就像要求将一件程序代码重写为OO代码.嗯...如果我将原始的fortran(或c)转换为java,那么我没有做更多的事情.如果我完全将其重写为OO范式,它将看起来不再像原始的Fortran或C一样 - 它将无法识别.
从OO设计到功能设计没有简单的映射.他们看问题的方式非常不同.
功能编程(例如所有编程样式)具有设计模式.关系数据库具有设计模式,OO具有设计模式,并且程序编程具有设计模式.一切都有设计模式,甚至是建筑物的建筑.
设计模式 - 作为一个概念 - 是一种永恒的建筑方式,无论技术或问题领域如何.但是,特定的设计模式适用于特定的问题域和技术.
每个思考自己在做什么的人都会发现设计模式.
其他推荐答案
Brian对语言和模式之间紧密联系的评论是
讨论的缺失部分是成语的概念.詹姆斯·奥·科普林(James O. Coplien)的书《高级C ++》在这里具有巨大的影响力.在他发现克里斯托弗·亚历山大(Christopher Alexander)和专栏没有名称的情况下很久(而且您也不能在不阅读亚历山大(Alexander)的情况下明智地谈论模式),他谈到了掌握成语在真正学习语言中的重要性.他以C中的字符串副本为例,while(*from++ = *to++);您可以将其视为缺少语言功能(或库功能)的创可贴,但实际上重要的是它是一个更大的思想单位或表达的单位,比其任何部分.
这就是模式和语言试图做的,以使我们更简洁地表达我们的意图.思想单位越丰富,您可以表达的思想就越复杂.在各种尺度上拥有丰富的,共享的词汇 - 从系统体系结构到偏斜 - 使我们能够进行更聪明的对话,并想到我们应该做的事情.
我们也可以作为个人学习.这是练习的全部要点.我们每个人都可以理解和使用我们永远无法想到自己的事物.语言,框架,图书馆,模式,成语等都在分享知识财富方面的位置.
问题描述
Since I started learning F# and OCaml last year, I've read a huge number of articles which insist that design patterns (especially in Java) are workarounds for the missing features in imperative languages. One article I found makes a fairly strong claim:
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.
The main features of functional programming (FP) include functions as first-class values, currying, immutable values, etc. It doesn't seem obvious to me that OO design patterns are approximating any of those features.
Additionally, in functional languages which support OOP (such as F# and OCaml), it seems obvious to me that programmers using these languages would use the same design patterns found available to every other OOP language. In fact, right now I use F# and OCaml every day, and there are no striking differences between the patterns I use in these languages vs. the patterns I use when I write in Java.
Is there any truth to the claim that functional programming eliminates the need for OOP design patterns? If so, could you post or link to an example of a typical OOP design pattern and its functional equivalent?
推荐答案
The blog post you quoted overstates its claim a bit. FP doesn't eliminate the need for design patterns. The term "design patterns" just isn't widely used to describe the same thing in FP languages. But they exist. Functional languages have plenty of best practice rules of the form "when you encounter problem X, use code that looks like Y", which is basically what a design pattern is.
However, it's correct that most OOP-specific design patterns are pretty much irrelevant in functional languages.
I don't think it should be particularly controversial to say that design patterns in general only exist to patch up shortcomings in the language. And if another language can solve the same problem trivially, that other language won't have need of a design pattern for it. Users of that language may not even be aware that the problem exists, because, well, it's not a problem in that language.
Here is what the Gang of Four has to say about this issue:
The choice of programming language is important because it influences one's point of view. Our patterns assume Smalltalk/C++-level language features, and that choice determines what can and cannot be implemented easily. If we assumed procedural languages, we might have included design patterns called "Inheritance", "Encapsulation," and "Polymorphism". Similarly, some of our patterns are supported directly by the less common object-oriented languages. CLOS has multi-methods, for example, which lessen the need for a pattern such as Visitor. In fact, there are enough differences between Smalltalk and C++ to mean that some patterns can be expressed more easily in one language than the other. (See Iterator for example.)
(The above is a quote from the Introduction to the Design Patterns book, page 4, paragraph 3)
The main features of functional programming include functions as first-class values, currying, immutable values, etc. It doesn't seem obvious to me that OO design patterns are approximating any of those features.
What is the command pattern, if not an approximation of first-class functions? :) In an FP language, you'd simply pass a function as the argument to another function. In an OOP language, you have to wrap up the function in a class, which you can instantiate and then pass that object to the other function. The effect is the same, but in OOP it's called a design pattern, and it takes a whole lot more code. And what is the abstract factory pattern, if not currying? Pass parameters to a function a bit at a time, to configure what kind of value it spits out when you finally call it.
So yes, several GoF design patterns are rendered redundant in FP languages, because more powerful and easier to use alternatives exist.
But of course there are still design patterns which are not solved by FP languages. What is the FP equivalent of a singleton? (Disregarding for a moment that singletons are generally a terrible pattern to use.)
And it works both ways too. As I said, FP has its design patterns too; people just don't usually think of them as such.
But you may have run across monads. What are they, if not a design pattern for "dealing with global state"? That's a problem that's so simple in OOP languages that no equivalent design pattern exists there.
We don't need a design pattern for "increment a static variable", or "read from that socket", because it's just what you do.
Saying a monad is a design pattern is as absurd as saying the Integers with their usual operations and zero element is a design pattern. No, a monad is a mathematical pattern, not a design pattern.
In (pure) functional languages, side effects and mutable state are impossible, unless you work around it with the monad "design pattern", or any of the other methods for allowing the same thing.
Additionally, in functional languages which support OOP (such as F# and OCaml), it seems obvious to me that programmers using these languages would use the same design patterns found available to every other OOP language. In fact, right now I use F# and OCaml everyday, and there are no striking differences between the patterns I use in these languages vs the patterns I use when I write in Java.
Perhaps because you're still thinking imperatively? A lot of people, after dealing with imperative languages all their lives, have a hard time giving up on that habit when they try a functional language. (I've seen some pretty funny attempts at F#, where literally every function was just a string of 'let' statements, basically as if you'd taken a C program, and replaced all semicolons with 'let'. :))
But another possibility might be that you just haven't realized that you're solving problems trivially which would require design patterns in an OOP language.
When you use currying, or pass a function as an argument to another, stop and think about how you'd do that in an OOP language.
Is there any truth to the claim that functional programming eliminates the need for OOP design patterns?
Yep. :) When you work in a FP language, you no longer need the OOP-specific design patterns. But you still need some general design patterns, like MVC or other non-OOP specific stuff, and you need a couple of new FP-specific "design patterns" instead. All languages have their shortcomings, and design patterns are usually how we work around them.
Anyway, you may find it interesting to try your hand at "cleaner" FP languages, like ML (my personal favorite, at least for learning purposes), or Haskell, where you don't have the OOP crutch to fall back on when you're faced with something new.
As expected, a few people objected to my definition of design patterns as "patching up shortcomings in a language", so here's my justification:
As already said, most design patterns are specific to one programming paradigm, or sometimes even one specific language. Often, they solve problems that only exist in that paradigm (see monads for FP, or abstract factories for OOP).
Why doesn't the abstract factory pattern exist in FP? Because the problem it tries to solve does not exist there.
So, if a problem exists in OOP languages, which does not exist in FP languages, then clearly that is a shortcoming of OOP languages. The problem can be solved, but your language does not do so, but requires a bunch of boilerplate code from you to work around it. Ideally, we'd like our programming language to magically make all problems go away. Any problem that is still there is in principle a shortcoming of the language. ;)
其他推荐答案
Is there any truth to the claim that functional programming eliminates the need for OOP design patterns?
Functional programming is not the same as object-oriented programming. Object-oriented design patterns don't apply to functional programming. Instead, you have functional programming design patterns.
For functional programming, you won't read the OO design pattern books; you'll read other books on FP design patterns.
language agnostic
Not totally. Only language-agnostic with respect to OO languages. The design patterns don't apply to procedural languages at all. They barely make sense in a relational database design context. They don't apply when designing a spreadsheet.
a typical OOP design pattern and its functional equivalent?
The above shouldn't exist. That's like asking for a piece of procedural code rewritten as OO code. Ummm... If I translate the original Fortran (or C) into Java, I haven't done anything more than translate it. If I totally rewrite it into an OO paradigm, it will no longer look anything like the original Fortran or C -- it will be unrecognizable.
There's no simple mapping from OO design to functional design. They're very different ways of looking at the problem.
Functional programming (like all styles of programming) has design patterns. Relational databases have design patterns, OO has design patterns, and procedural programming has design patterns. Everything has design patterns, even the architecture of buildings.
Design patterns -- as a concept -- are a timeless way of building, irrespective of technology or problem domain. However, specific design patterns apply to specific problem domains and technologies.
Everyone who thinks about what they're doing will uncover design patterns.
其他推荐答案
Brian's comments on the tight linkage between language and pattern is to the point,
The missing part of this discussion is the concept of idiom. James O. Coplien's book, "Advanced C++" was a huge influence here. Long before he discovered Christopher Alexander and the Column Without a Name (and you can't talk sensibly about patterns without reading Alexander either), he talked about the importance of mastering idioms in truly learning a language. He used string copy in C as an example, while(*from++ = *to++); You can see this as a bandaid for a missing language feature (or library feature), but what really matters about it is that it's a larger unit of thought, or of expression, than any of its parts.
That is what patterns, and languages, are trying to do, to allow us to express our intentions more succinctly. The richer the units of thought the more complex the thoughts you can express. Having a rich, shared vocabulary at a range of scales - from system architecture down to bit twiddling - allows us to have more intelligent conversations, and thoughts about what we should be doing.
We can also, as individuals, learn. Which is the entire point of the exercise. We each can understand and use things we would never be able to think of ourselves. Languages, frameworks, libraries, patterns, idioms and so on all have their place in sharing the intellectual wealth.