Program Tip

함수형 프로그래밍이 GoF 디자인 패턴을 대체합니까?

programtip 2020. 9. 27. 13:46
반응형

함수형 프로그래밍이 GoF 디자인 패턴을 대체합니까? [닫은]


작년에 F #과 OCaml을 배우기 시작한 이후로 디자인 패턴 (특히 Java)이 명령형 언어의 누락 된 기능에 대한 해결 방법이라고 주장하는 수많은 기사를 읽었습니다. 내가 찾은 한 기사 는 상당히 강력한 주장을합니다 .

내가 만난 대부분의 사람들은 Gang of Four의 Design Patterns 책을 읽었습니다. 자존심이 강한 프로그래머라면이 책이 언어에 구애받지 않고 패턴이 일반적으로 사용하는 언어에 관계없이 소프트웨어 엔지니어링에 적용된다고 말할 것입니다. 이것은 고귀한 주장입니다. 불행히도 그것은 진실과는 거리가 멀다.

기능적 언어는 표현력이 매우 뛰어납니다. 기능적 언어에서는 언어가 매우 높은 수준 일 가능성이 높기 때문에 디자인 패턴이 필요하지 않으므로 디자인 패턴을 모두 제거하는 개념으로 프로그래밍하게됩니다.

함수형 프로그래밍의 주요 기능에는 일류 값, 커링, 불변 값 등의 함수가 포함됩니다. OO 디자인 패턴이 이러한 기능에 근접하고 있다는 것이 분명하지 않습니다.

또한 OOP를 지원하는 기능적 언어 (예 : F # 및 OCaml)에서 이러한 언어를 사용하는 프로그래머는 다른 모든 OOP 언어에서 사용할 수있는 동일한 디자인 패턴을 사용한다는 것이 분명해 보입니다. 사실 지금은 매일 F #과 OCaml을 사용하고 있으며 이러한 언어에서 사용하는 패턴과 Java로 작성할 때 사용하는 패턴 사이에는 현저한 차이가 없습니다.

함수형 프로그래밍이 OOP 디자인 패턴의 필요성을 제거한다는 주장에 진실이 있습니까? 그렇다면 일반적인 OOP 디자인 패턴과 그에 상응하는 기능의 예를 게시하거나 링크 할 수 있습니까?


인용 한 블로그 게시물은 그 주장을 약간 과장합니다. FP는 디자인 패턴의 필요성을 제거 하지 않습니다 . "디자인 패턴"이라는 용어는 FP 언어에서 동일한 것을 설명하는 데 널리 사용되지 않습니다. 그러나 그들은 존재합니다. 기능적 언어에는 "문제 X가 발생하면 Y처럼 보이는 코드를 사용하십시오"라는 형식의 모범 사례 규칙이 많이 있습니다. 기본적으로 디자인 패턴이 있습니다.

그러나 대부분의 OOP 특정 디자인 패턴이 기능 언어와 거의 관련이 없다는 것은 옳습니다.

일반적으로 디자인 패턴 은 언어의 단점을 보완하기 위해서만 존재 한다고 말하는 것이 특히 논란의 여지가 없다고 생각합니다 . 그리고 다른 언어가 동일한 문제를 사소하게 해결할 수 있다면 다른 언어는 디자인 패턴이 필요하지 않을 것입니다. 해당 언어의 사용자는 문제 가 존재 한다는 사실조차 인식하지 못할 수도 있습니다 . 왜냐하면 해당 언어에서는 문제 아니기 때문입니다.

다음은 Gang of Four가이 문제에 대해 말한 내용입니다.

프로그래밍 언어의 선택은 자신의 관점에 영향을주기 때문에 중요합니다. 우리의 패턴은 스몰 토크 / C ++ 수준의 언어 기능을 가정하고 그 선택에 따라 쉽게 구현할 수있는 것과 구현할 수없는 것이 결정됩니다. 절차 적 언어를 가정했다면 "상속", "캡슐화"및 "다형성"이라는 디자인 패턴을 포함했을 수 있습니다. 마찬가지로, 일부 패턴은 덜 일반적인 객체 지향 언어에서 직접 지원됩니다. 예를 들어 CLOS에는 방문자와 같은 패턴의 필요성을 줄이는 다중 방법이 있습니다. 사실, 스몰 토크와 C ++ 사이에는 충분한 차이가있어서 어떤 패턴은 다른 언어보다 한 언어로 더 쉽게 표현할 수 있습니다. (예를 들어 반복자를 참조하십시오.)

(위는 Introduction to the Design Patterns book, page 4, paragraph 3에서 인용 한 것입니다)

함수형 프로그래밍의 주요 기능에는 일류 값, 커링, 불변 값 등의 함수가 포함됩니다. OO 디자인 패턴이 이러한 기능에 근접하고 있다는 것이 분명하지 않습니다.

일류 함수의 근사치가 아니라면 명령 패턴은 무엇입니까? :) FP 언어에서는 단순히 함수를 다른 함수의 인수로 전달합니다. OOP 언어에서는 함수를 클래스로 래핑해야하며,이를 인스턴스화 한 다음 해당 객체를 다른 함수로 전달할 수 있습니다. 효과는 동일하지만 OOP에서는 디자인 패턴이라고하며 훨씬 더 많은 코드가 필요합니다. 그리고 커링이 아니라면 추상적 인 팩토리 패턴은 무엇입니까? 매개 변수를 한 번에 조금씩 함수에 전달하여 마지막으로 호출 할 때 어떤 종류의 값을 내뿜는 지 구성합니다.

예, 더 강력하고 사용하기 쉬운 대안이 존재하기 때문에 여러 GoF 디자인 패턴이 FP 언어에서 중복으로 렌더링됩니다.

그러나 물론 여전히 FP 언어로 해결 되지 않는 디자인 패턴이 있습니다. 싱글 톤과 동등한 FP는 무엇입니까? (싱글 톤이 일반적으로 사용하기에 끔찍한 패턴이라는 것을 잠시 무시하십시오)

그리고 두 가지 방식으로도 작동합니다. 내가 말했듯이, FP는 디자인 패턴도 가지고 있습니다. 사람들은 보통 그것들을 그렇게 생각하지 않습니다.

그러나 모나드를 만났을 수도 있습니다. "글로벌 상태 처리"를위한 디자인 패턴이 아니라면 무엇입니까? 이것은 OOP 언어에서 매우 단순해서 동등한 디자인 패턴이 존재하지 않는 문제입니다.

당신이 단지 무엇 때문에, "그 소켓에서 읽기" "정적 변수를 증가", 또는 위해 우리는 디자인 패턴이 필요하지 않습니다 .

Monad가 디자인 패턴이라고 말하는 것은 Integers가 일반적인 작업을하고 0 요소가 디자인 패턴이라고 말하는 것만 큼 터무니 없습니다. 아니요, Monad는 디자인 패턴 이 아니라 수학적 패턴 입니다.

(순수한) 기능적 언어에서는 모나드 "디자인 패턴"또는 동일한 것을 허용하는 다른 방법으로 해결하지 않는 한 부작용과 변경 가능한 상태가 불가능합니다.

또한 OOP를 지원하는 기능적 언어 (예 : F # 및 OCaml)에서 이러한 언어를 사용하는 프로그래머는 다른 모든 OOP 언어에서 사용할 수있는 동일한 디자인 패턴을 사용한다는 것이 분명해 보입니다. 사실 지금은 매일 F #과 OCaml을 사용하고 있으며 이러한 언어에서 사용하는 패턴과 Java로 작성할 때 사용하는 패턴 사이에는 현저한 차이가 없습니다.

아마도 당신이 여전히 명령 적으로 생각하고 있기 때문일까요? 많은 사람들은 평생 명령형 언어를 다룬 후 기능적 언어를 시도 할 때 그 습관을 포기하는 데 어려움을 겪습니다. (저는 F #에서 꽤 재미있는 시도를 보았습니다. 문자 그대로 모든 함수는 기본적으로 C 프로그램을 사용하고 모든 세미콜론을 'let'으로 바꾼 것처럼 'let'문 문자열 일뿐입니다. :))

그러나 또 다른 가능성은 OOP 언어의 디자인 패턴이 필요한 문제를 사소하게 해결하고 있다는 것을 깨닫지 못했을 수 있습니다.

커링을 사용하거나 다른 함수에 대한 인수로 함수를 전달할 때 중지하고 OOP 언어에서 수행 할 방법에 대해 생각하십시오.

함수형 프로그래밍이 OOP 디자인 패턴의 필요성을 제거한다는 주장에 진실이 있습니까?

네. :) FP 언어로 작업 할 때 더 이상 OOP 특정 디자인 패턴이 필요하지 않습니다. 그러나 여전히 MVC 또는 기타 비 OOP 특정 항목과 같은 일반적인 디자인 패턴이 필요하며 대신 몇 가지 새로운 FP 특정 "디자인 패턴"이 필요합니다. 모든 언어에는 단점이 있으며 디자인 패턴은 일반적으로 이러한 문제를 해결하는 방식입니다.

어쨌든, ML (적어도 학습 목적으로 개인적으로 좋아하는)이나 Haskell과 같은 "깨끗한"FP 언어를 사용해 보는 것이 흥미로울 수 있습니다. 여기서는 OOP 목발이없는 경우 새로운 것에 직면했습니다.


예상대로, 몇몇 사람들은 "언어의 결점을 패치하는"디자인 패턴의 정의에 반대했습니다. 그래서 여기에 저의 정당성이 있습니다. 이미 말했듯이 대부분의 디자인 패턴은 하나의 프로그래밍 패러다임 또는 때로는 하나의 특정 언어에만 적용됩니다. 종종 그들은 해당 패러다임 에만 존재 하는 문제를 해결합니다 (FP 용 모나드 또는 OOP 용 추상 팩토리 참조). 추상 팩토리 패턴이 FP에 존재하지 않는 이유는 무엇입니까? 해결하려는 문제가 거기에 존재하지 않기 때문입니다. 따라서 FP 언어에 존재하지 않는 OOP 언어에 문제가있는 경우 이는 분명히 OOP 언어의 단점입니다. 문제는 해결 될 수 있지만 귀하의 언어는 그렇게하지 않지만 문제를 해결하기 위해서는 많은 상용구 코드가 필요합니다. 이상적으로 우리는모든 문제가 사라집니다. 여전히 존재하는 문제는 원칙적으로 언어의 결점입니다. ;)


함수형 프로그래밍이 OOP 디자인 패턴의 필요성을 제거한다는 주장에 진실이 있습니까?

함수형 프로그래밍은 객체 지향 프로그래밍과 다릅니다. 객체 지향 디자인 패턴은 함수형 프로그래밍에 적용되지 않습니다. 대신 함수형 프로그래밍 디자인 패턴이 있습니다.

함수형 프로그래밍의 경우 OO 디자인 패턴 책을 읽지 않고 FP 디자인 패턴에 대한 다른 책을 읽습니다.

언어 불가지론

완전히는 아닙니다. OO 언어와 관련하여 언어에 구애받지 않습니다. 디자인 패턴은 절차 적 언어에는 전혀 적용되지 않습니다. 관계형 데이터베이스 디자인 컨텍스트에서는 거의 의미가 없습니다. 스프레드 시트를 디자인 할 때는 적용되지 않습니다.

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, 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. 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 idiom 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.


The GOF book explicitly ties itself to OOP - the title is Design Patterns - Elements of Reusable Object-Oriented Software (emphasis mine.)


Design Patterns in Dynamic Programming by Peter Norvig has thoughtful coverage of this general theme, though about 'dynamic' languages instead of 'functional' (there's overlap).


Here's another link, discussing this topic: http://blog.ezyang.com/2010/05/design-patterns-in-haskel/

In his blog post Edward describes all 23 original GoF patterns in terms of Haskell.


When you try to look at this at the level of "design patterns" (in general) and "FP versus OOP", the answers you'll find will be murky at best.

Go a level deeper on both axes, though, and consider specific design patterns and specific language features and things become clearer.

So, for example, some specific patterns, like Visitor, Strategy, Command, and Observer definitely change or disappear when using a language with algebraic data types and pattern matching, closures, first class functions, etc. Some other patterns from the GoF book still 'stick around', though.

In general, I would say that, over time, specific patterns are being eliminated by new (or just rising-in-popularity) language features. This is the natural course of language design; as languages become more high-level, abstractions that could previously only be called out in a book using examples now become applications of a particular language feature or library.

(Aside: here's a recent blog I wrote, which has other links to more discussion on FP and design patterns.)


Norvig's presentation alludes to an analysis they did of all the GoF patterns, and they say that 16 of the 23 patterns had simpler implementations in functional languages, or were simply part of the language. So presumably at least seven of them either were a) equally complicated or b) not present in the language. Unfortunately for us, they are not enumerated!

I think it's clear that most of the "creational" or "structural" patterns in GoF are merely tricks to get the primitive type systems in Java or C++ to do what you want. But the rest are worthy of consideration no matter what language you program in.

One might be Prototype; while it is a fundamental notion of JavaScript, it has to be implemented from scratch in other languages.

One of my favorite patterns is the Null Object pattern: represent the absence of something as an object that does an appropriate kind of nothing. This may be easier to model in a functional language. However, the real achievement is the shift in perspective.


I would say that when you have a language like Lisp with its support for macros, then you can build you own domain-specific abstractions, abstractions which often are much better than the general idiom solutions.


And even the OO Design Pattern solutions are language specific. Design patterns are solutions to common problems that your programming language doesn't solve for you. In Java, the Singleton pattern solves the one-of-something (simplified) problem. In Scala, you have a top level construct called Object in addition to Class. It's lazily instantiated and there is only one. You don't have to use the Singleton pattern to get a Singleton. It's part of the language.


As others have said, there are patterns specific of functional programming. I think the issue of getting rid of design patterns is not so much a matter of switching to functional, but a matter of language features.

Take a look at how Scala does away with the "singleton pattern": you simply declare an object instead of a class. Another feature, pattern matching, helps avoiding the clunkiness of the visitor pattern. See the comparison here: http://andymaleh.blogspot.com/2008/04/scalas-pattern-matching-visitor-pattern.html

And Scala, like F#, is a fusion of OO-functional. I don't know about F# but it probably has this kind of features.

Closures are present in functional language, but need not be restricted to them. They help with the delegator pattern.

One more observation. This piece of code implements a pattern: it's such a classic and it's so elemental that we don't usually think of it as a "pattern", but it sure is:

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

Imperative languages like Java and C# have adopted what is essentially a functional construct to deal with this: "foreach".


Patterns are ways of solving similar problems that get seen again and again, and then get described and documented. So no, FP is not going to replace patterns; however, FP might create new patterns, and make some current "best practices" patterns "obsolete".


The GoF Design Patterns are coding workaround recipes for OO languages that are descendants of Simula 67, like Java and C++.

Most of the "ills" treated by the design patterns are caused by:

  • 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".

There isn't a single one of these design patterns that doesn't disappear in the Common Lisp Object System, even though the solution is structured in essentially the same way as in the corresponding design pattern. (Moreover, that object system precedes the GoF book by well over a decade. Common Lisp became an ANSI standard the same year that that book was first published.)

As far as functional programming is concerned, whether or not the patterns apply to it depends on whether the given functional programming language has some kind of object system, and whether it is modeled after the object systems which benefit from the patterns. That type of object-orientation does not mix well with functional programming, because the mutation of state is at the front and centre.

Construction and non-mutating access are compatible with functional programming, and so patterns which have to do with abstracting access or construction could be applicable: patterns like Factory, Facade, Proxy, Decorator, Visitor.

On the other hand, the behavioral patterns like State and Strategy probably do not directly apply in functional OOP because mutation of state is at their core. This doesn't mean they don't apply; perhaps they somehow apply in combination with whatever tricks are available for simulating mutable state.


I'd like to plug a couple of excellent but somewhat dense papers by Jeremy Gibbons: "Design patterns as higher-order datatype-generic programs" and "The essence of the Iterator pattern" (both available here: http://www.comlab.ox.ac.uk/jeremy.gibbons/publications/).

These both describe how idiomatic functional constructs cover the terrain that is covered by specific design patterns in other (object-oriented) settings.


You can't have this discussion without bringing up type systems.

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.

That's because these features don't address the same issues that OOP does... they are alternatives to imperative programming. The FP answer to OOP lies in the type systems of ML and Haskell... specifically sum types, abstract data types, ML modules, Haskell typeclasses.

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)

The first thing typeclasses do is eliminate the need for singletons.

You could go through the list of 23 and eliminate more, but I don't have time to right now.


I think only two GoF Design Patterns are designed to introduce the functional programming logic into natural OO language. I think about Strategy and Command. Some of the other GoF design patterns can be modified by functional programming to simplify the design and keep the purpose.


Essentially, yes!

  • When a pattern circumvents the missing features (high order functions, stream handling...) that ultimalty facilitate composition.
  • The need to re-write patterns' implementation again and again can itself be seen as a language smell.

Besides, this page (AreDesignPatternsMissingLanguageFeatures) provides a "pattern/feature" translation table and some nice discussions, if you are willing to dig.


Functional programming does not replace design patterns. Design patterns can not be replaced.

Patterns simply exist; they emerged over time. The GoF book formalized some of them. If new patterns are coming to light as developers use functional programming languages that is exciting stuff, and perhaps there will be books written about them as well.


OOP and the GoF patterns deal with states. OOP models reality to keep the code base as near as possible to the given requirements of reality. GoF design patterns are patterns that were identified to solve atomic real world problems. They handle the problem of state in a semantic way.

As in real functional programming no state exists, it does not make sense to apply the GoF patterns. There are not functional design patterns in the same way there are GoF design patterns. Every functional design pattern is artifical in contrast to reality as functions are constructs of math and not reality.

Functions lack the concept of time as they are always return the same value whatever the current time is unless time is part of the function parameters what makes it really hard to prrocess "future requests". Hybrid languages mix those concepts make the languages not real functional programming languages.

Functional languages are rising only because of one thing: the current natural restrictions of physics. Todays processors are limited in their speed of processing instructions due to physical laws. You see a stagnation in clock frequency but an expansion in processing cores. Thats why parallelism of instructions becomes more and more important to increase speed of modern applications. As functional programming by definition has no state and therefore has no side effects it is safe to process functions safely in parallel.

GoF patterns are not obsolete. They are at least necessary to model the real world requirements. But if you use a functional programming language you have to transform them into their hybrid equivalents. Finally you have no chance to make only functional programs if you use persistence. For the hybrid elements of your program there remains the necessity to use GoF patterns. Any other element that is purely functional there is no necessity to use GoF patterns because there is no state.

Because the GoF pattern are not necessary for real functional programming that doesn't mean that the SOLID principles should not be applied. The SOLID principles are beyond any language paradigm.


In the new 2013 book named "Functional Programming Patterns- in Scala and Clojure" the author Michael.B. Linn does a decent job comparing and providing replacements in many cases for the GoF patterns and also discusses the newer functional patterns like 'tail recursion', 'memoization', 'lazy sequence', etc.

This book is available on Amazon. I found it very informative and encouraging when coming from an OO background of a couple of decades.


In Functional Programming, design patterns have a different meaning, in fact, most of OOP design patterns are unnecessary in Functional programming because of the higher level of abstraction and HOFs used as building blocks.

The principle of an HOF means that functions can be passed as arguments to other functions. and functions can return values.


I think that each paradigm serves a different purpose and as such cannot be compared in this way.

I have not heard that the GoF design patterns are applicable to every language. I have heard that they are applicable to all OOP languages. If you use Functional programming then the domain of problems that you solve is different from OO languages.

I wouldn't use functional language to write a user interface but one of the OO languages like C# or Java would make this job easier. If I were writing a functional language then I wouldn't consider using OO Design Patterns.


OOP and FP have different goals, OOP aims to encapsulate the complexities/moving parts of software components and FP aims to minimize the complexity and dependencies of software components however these 2 paradigms are not necessarily 100% contradicting and could be applied together to get the benefit from both worlds. Even with a language that does not natively support functional programming like C#, you could write functional code if you understand the FP principles, likewise you could apply OOP principles using F# if you understand OOP principles, patterns and best practices. You would make the right choice based on the situation and problem that you try to solve, regardless of the programming language you use.


As the accepted answer said, OOP and FP all have their specific patterns.

However, there are some patterns which are so common that all programming platforms I can think of should have. Here is an (incomplete) list:

  • Adapter. I can hardly think of a useful programming platform which is so comprehensive (and self-fulfilled) that it does not need to talk to the world. If it is going to do so, an adapter is definitely needed.

  • Façade. Any programming platforms that can handle big source code should be able to modularise. If you were to create a module for other parts of the program, you will want to hide the "dirty" parts of the code and give it a nice interface.

  • Interpreter. In general, any program is just doing two things: parse input and print output. Mouse inputs need to be parsed, and window widgets need to be printed out. Therefore, having an embedded interpreter gives the program additional power to customise things.

Also, I noticed in a typical FP language, Haskell, there is something similar to GoF patterns, but with different names. In my opinion this suggest they were there because there are some common problems to solve in both FP and OOP languages.

  • Monad transformer and decorator. The former used to add additional ability into an existing monad, the latter add additional ability to an existing object.

참고URL : https://stackoverflow.com/questions/327955/does-functional-programming-replace-gof-design-patterns

반응형