it-swarm.com.de

Ersetzt funktionale Programmierung GoF-Designmuster?

Seitdem ich im letzten Jahr mit dem Erlernen von F # und OCaml begonnen habe, habe ich eine Vielzahl von Artikeln gelesen, in denen darauf bestanden wird, dass Entwurfsmuster (insbesondere in Java) Problemumgehungen für die fehlenden Funktionen in imperativen Sprachen sind. Ein Artikel, den ich gefunden habe macht eine ziemlich starke Behauptung :

Die meisten Leute, die ich getroffen habe, haben das Design Patterns-Buch der Gang of Four gelesen. Jeder Programmierer mit Selbstachtung wird Ihnen sagen, dass das Buch sprachunabhängig ist und die Muster für die Softwareentwicklung im Allgemeinen gelten, unabhängig davon, welche Sprache Sie verwenden. Dies ist eine noble Behauptung. Leider ist es weit von der Wahrheit entfernt.

Funktionssprachen sind äußerst ausdrucksstark. In einer funktionalen Sprache braucht man keine Entwurfsmuster, weil die Sprache wahrscheinlich so hoch ist, dass man am Ende in Konzepten programmiert, die Entwurfsmuster insgesamt eliminieren.

Zu den Hauptmerkmalen der funktionalen Programmierung gehören Funktionen wie erstklassige Werte, Aktualisierungen, unveränderliche Werte usw. Für mich scheint es nicht offensichtlich, dass OO) Entwurfsmuster sich einem dieser Merkmale annähern.

Darüber hinaus scheint es mir in funktionalen Sprachen, die OOP (wie F # und OCaml) unterstützen, offensichtlich, dass Programmierer, die diese Sprachen verwenden, die gleichen Entwurfsmuster verwenden, die für alle anderen verfügbar sind OOP language. Tatsächlich verwende ich derzeit jeden Tag F # und OCaml, und es gibt keine auffälligen Unterschiede zwischen den Mustern, die ich in diesen Sprachen verwende, und den Mustern, die ich beim Schreiben in Java verwende.

Ist die Behauptung, dass die funktionale Programmierung die Notwendigkeit von OOP= Entwurfsmustern beseitigt? Wenn ja, könnten Sie ein Beispiel für ein typisches OOP) posten oder verlinken? = Designmuster und dessen funktionales Äquivalent?

1016
Juliet

Ist die Behauptung, dass die funktionale Programmierung die Notwendigkeit von OOP Entwurfsmustern beseitigt, wahr?

Funktionale Programmierung ist nicht dasselbe wie objektorientierte Programmierung. Objektorientierte Entwurfsmuster gelten nicht für die funktionale Programmierung. Stattdessen verfügen Sie über funktionale Programmierentwurfsmuster.

Zur funktionalen Programmierung lesen Sie nicht die OO Designmusterbücher, sondern andere Bücher zu FP Designmustern.

sprachunabhängig

Nicht völlig. Nur sprachunabhängig in Bezug auf OO Sprachen. Die Entwurfsmuster gelten überhaupt nicht für prozedurale Sprachen. Sie sind in einem relationalen Datenbankentwurfskontext kaum sinnvoll. Sie gelten nicht beim Entwerfen einer Tabelle.

ein typisches OOP Designmuster und sein funktionales Äquivalent?

Das obige sollte nicht existieren. Das ist so, als würden Sie nach einem Teil des Prozedurcodes fragen, der als OO-Code umgeschrieben wurde. Ähm ... Wenn ich den ursprünglichen Fortran (oder C) in Java übersetze, habe ich nichts weiter getan, als ihn zu übersetzen. Wenn ich es komplett in ein OO Paradigma umschreibe, wird es nicht mehr so ​​aussehen wie das ursprüngliche Fortran oder C - es wird nicht wiederzuerkennen sein.

Es gibt keine einfache Zuordnung von OO Design zu Functional Design. Es sind sehr unterschiedliche Sichtweisen auf das Problem.

Funktionale Programmierung (wie alle Programmierstile) hat Designmuster. Relationale Datenbanken haben Entwurfsmuster, OO hat Entwurfsmuster, die prozedurale Programmierung hat Entwurfsmuster. Alles hat Designmuster, sogar die Architektur von Gebäuden.

Design Patterns - als Konzept - sind eine zeitlose Art des Bauens, unabhängig von Technologie oder Problemdomäne. Bestimmte Entwurfsmuster gelten jedoch für bestimmte Problembereiche und Technologien.

Jeder, der darüber nachdenkt, was er tut, wird Designmuster aufdecken.

146
S.Lott

Brians Kommentare zur engen Verknüpfung von Sprache und Muster sind auf den Punkt gebracht:

Der fehlende Teil dieser Diskussion ist das Konzept der Redewendung. Copliens Buch "Advanced C++" hatte hier einen großen Einfluss. Lange bevor er Christopher Alexander und die Spalte ohne Namen entdeckte (und man kann nicht sinnvoll über Muster sprechen, ohne Alexander zu lesen), sprach er darüber, wie wichtig es ist, Redewendungen zu beherrschen, um wirklich eine Sprache zu lernen. In C verwendete er als Beispiel string copy, while (* from ++ = * to ++); Sie können dies als Bandaid für ein fehlendes Sprachmerkmal (oder Bibliotheksmerkmal) ansehen, aber was wirklich wichtig ist, ist, dass es sich um eine größere Einheit von Gedanken oder Ausdruck handelt als alle ihre Teile.

Das ist es, was Muster und Sprachen zu tun versuchen, damit wir unsere Absichten prägnanter ausdrücken können. Je reicher die Gedankeneinheiten, desto komplexer die Gedanken, die Sie ausdrücken können. Ein umfangreiches, gemeinsames Vokabular in einer Reihe von Bereichen - von der Systemarchitektur bis hin zum kleinen Rätsel - ermöglicht es uns, intelligentere Gespräche zu führen und uns Gedanken darüber zu machen, was wir tun sollten.

Wir können auch als Individuen lernen. Welches ist der ganze Punkt der Übung. Wir alle können Dinge verstehen und anwenden, die wir niemals an uns selbst denken könnten. Sprachen, Frameworks, Bibliotheken, Muster, Redewendungen usw. haben alle ihren Platz im Teilen des geistigen Reichtums.

44
grahamsw

Das GOF-Buch bindet sich ausdrücklich an OOP - der Titel lautet Design Patterns - Elements of Reusable Object-Oriented Software (Schwerpunkt Mine.)

39
bright

Design Patterns in Dynamic Programming von Peter Norvig behandelt dieses allgemeine Thema nachdenklich, obwohl es sich um "dynamische" Sprachen handelt, anstatt um "funktionale" (es gibt Überlappungen).

33
Darius Bacon

Hier ist ein weiterer Link, der dieses Thema behandelt: http://blog.ezyang.com/2010/05/design-patterns-in-haskel/

In seinem Blog-Beitrag beschreibt Edward alle 23 ursprünglichen GoF-Muster in Bezug auf Haskell.

25
folone

Wenn Sie versuchen, dies auf der Ebene der "Design Patterns" (allgemein) und "FP versus OOP" zu betrachten, werden Sie bestenfalls trübe Antworten finden.

Gehen Sie jedoch auf beiden Achsen eine Ebene tiefer und betrachten Sie spezifische Entwurfsmuster und spezifische Sprachfunktionen und die Dinge werden klarer.

So zum Beispiel einige spezifische Muster, wie Besucher , Strategie , Befehl und Beobachter ändern sich definitiv oder verschwinden, wenn eine Sprache mit algebraische Datentypen und Musterabgleich , Abschlüsse , erstklassige Funktionen , usw. Einige andere Muster aus dem GoF-Buch bleiben jedoch weiterhin erhalten.

Im Allgemeinen würde ich sagen, dass bestimmte Muster im Laufe der Zeit durch neue (oder nur in der Popularität aufsteigende) Sprachfunktionen beseitigt werden. Dies ist der natürliche Ablauf der Sprachgestaltung; Da Sprachen immer höherstufiger werden, werden Abstraktionen, die zuvor nur in einem Buch anhand von Beispielen beschrieben wurden, nun zu Anwendungen eines bestimmten Sprachfeatures oder einer bestimmten Bibliothek.

(Nebenbei: hier ist ein kürzlich veröffentlichter Blog Ich habe geschrieben, der andere Links zu weiteren Diskussionen über FP und Entwurfsmuster enthält.)

19
Brian

Norvigs Präsentation spielt auf eine Analyse aller GoF-Muster an, und sie sagen, dass 16 der 23 Muster einfachere Implementierungen in funktionalen Sprachen hatten oder einfach Teil der Sprache waren. Vermutlich waren also mindestens sieben von ihnen entweder a) gleich kompliziert oder b) nicht in der Sprache vorhanden. Leider für uns sind sie nicht aufgezählt!

Ich denke, es ist klar, dass die meisten "kreativen" oder "strukturellen" Muster in GoF nur Tricks sind, um die primitiven Typsysteme in Java oder C++ zu bekommen, um das zu tun, was Sie wollen. Aber der Rest ist Überlegenswert, egal in welcher Sprache Sie programmieren.

Man könnte Prototyp sein; Während es ein grundlegender Begriff von JavaScript ist, muss es in anderen Sprachen von Grund auf neu implementiert werden.

Eines meiner Lieblingsmuster ist das Null-Objekt-Muster: Stellen Sie die Abwesenheit von etwas als Objekt dar, das eine angemessene Art von Nichts bewirkt. Dies ist möglicherweise einfacher in einer funktionalen Sprache zu modellieren. Der eigentliche Erfolg ist jedoch der Perspektivwechsel.

16

Ich würde sagen, wenn Sie eine Sprache wie LISP haben, die Makros unterstützt, können Sie eigene domänenspezifische Abstraktionen erstellen, die oft viel besser sind als die allgemeinen Redewendungen.

15

Sogar die OO Design Pattern-Lösungen sind sprachspezifisch. Design Patterns sind Lösungen für häufige Probleme, die Ihre Programmiersprache für Sie nicht löst. In Java löst das Singleton-Muster die Ein (vereinfachtes) Problem: In Scala gibt es zusätzlich zu Class ein Konstrukt der obersten Ebene mit dem Namen Object. Es wird träge instanziiert und es gibt nur ein einziges. Sie müssen nicht das Singleton-Muster verwenden, um ein Singleton zu erhalten Sprache.

9
Dan Sickles

Muster sind Methoden zur Lösung ähnlicher Probleme, die immer wieder auftauchen und anschließend beschrieben und dokumentiert werden. Also nein, FP ersetzt keine Muster, FP= erstellt jedoch möglicherweise neue Muster und macht einige aktuelle "Best Practices" -Muster "obsolet".

8
Edwin Buck

Wie andere gesagt haben, gibt es spezifische Muster für die funktionale Programmierung. Ich denke, das Problem, Designmuster loszuwerden, ist nicht so sehr eine Frage des Wechsels zu funktionalen, sondern eine Frage der Sprachfunktionen .

Schauen Sie sich an, wie Scala das "Singleton-Muster" beseitigt: Sie deklarieren einfach ein Objekt anstelle eines Eine weitere Funktion, Pattern Matching, hilft dabei, die Klobigkeit des Besuchermusters zu vermeiden. Den Vergleich finden Sie hier: http: //andymaleh.blogspot.com/2008/04/scalas-pattern-matching-visitor- pattern.html

Und Scala ist wie F # eine Fusion von OO-Funktionen. Ich kenne F # nicht, aber es hat wahrscheinlich diese Art von Funktionen.

Abschlüsse sind in funktionaler Sprache vorhanden, müssen aber nicht auf diese beschränkt sein. Sie helfen beim Delegator-Pattern.

Noch eine Beobachtung. Dieser Code implementiert ein Muster: Es ist so klassisch und so elementar, dass wir es normalerweise nicht als "Muster" betrachten, aber es ist sicher:

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

Imperative Sprachen wie Java und C # haben das angenommen, was im Wesentlichen ein funktionales Konstrukt ist, um damit umzugehen: "foreach".

8
Germán

Die GoF-Entwurfsmuster sind Umgehungsrezepte für OO= Sprachen, die Nachkommen von Simula 67 sind, wie Java und C++.

Die meisten von den Entwurfsmustern behandelten "Übel" werden verursacht durch:

  • statisch typisierte Klassen, die Objekte angeben, aber selbst keine Objekte sind;
  • beschränkung auf den Einzelversand (nur das am weitesten links stehende Argument wird zur Auswahl einer Methode verwendet, die restlichen Argumente werden nur als statische Typen betrachtet: Wenn es sich um dynamische Typen handelt, ist es Sache der Methode, dies mit Ad-hoc-Ansätzen zu regeln);
  • unterscheidung zwischen regulären Funktionsaufrufen und objektorientierten Funktionsaufrufen, was bedeutet, dass objektorientierte Funktionen nicht als Funktionsargumente übergeben werden können, wenn reguläre Funktionen erwartet werden und umgekehrt; und
  • unterscheidung zwischen "Basistypen" und "Klassentypen".

Es gibt kein einziges dieser Entwurfsmuster, das im Common LISP Object System nicht verschwindet, obwohl die Lösung im Wesentlichen wie im entsprechenden Entwurfsmuster aufgebaut ist. (Darüber hinaus geht dieses Objektsystem dem GoF-Buch weit über ein Jahrzehnt voraus. Common LISP wurde im selben Jahr, in dem das Buch erstmals veröffentlicht wurde, zum ANSI-Standard.)

Ob die Muster für die funktionale Programmierung gelten oder nicht, hängt davon ab, ob die gegebene funktionale Programmiersprache über ein Objektsystem verfügt und ob sie den Objektsystemen nachempfunden ist, die von den Mustern profitieren. Diese Art der Objektorientierung passt nicht gut zur funktionalen Programmierung, da die Mutation des Zustands im Vordergrund und im Zentrum steht.

Konstruktion und nicht mutierender Zugriff sind mit der funktionalen Programmierung kompatibel, daher können Muster anwendbar sein, die mit abstrahierendem Zugriff oder Konstruktion zu tun haben: Muster wie Factory, Facade, Proxy, Decorator, Visitor.

Andererseits gelten Verhaltensmuster wie State und Strategy wahrscheinlich nicht direkt für Functional OOP, da die Mutation des Zustands im Mittelpunkt steht. Das bedeutet nicht sie treffen nicht zu, vielleicht treffen sie in Kombination mit den Tricks zu, die zur Simulation eines veränderlichen Zustands zur Verfügung stehen.

8
Kaz

Ich möchte ein paar exzellente, aber etwas dichte Artikel von Jeremy Gibbons einstecken: "Entwurfsmuster als generische Programme für Datentypen höherer Ordnung" und "Die Essenz des Iterator-Musters" (beide hier verfügbar: http: //www.comlab.ox.ac.uk/jeremy.gibbons/publications/ ).

Diese beiden beschreiben, wie idiomatische Funktionskonstruktionen das Terrain abdecken, das in anderen (objektorientierten) Umgebungen von bestimmten Entwurfsmustern abgedeckt wird.

7
sclv

Sie können diese Diskussion nicht führen, ohne Typsysteme aufzurufen.

Zu den Hauptmerkmalen der funktionalen Programmierung gehören Funktionen wie erstklassige Werte, Aktualisierungen, unveränderliche Werte usw. Für mich scheint es nicht offensichtlich, dass OO) Entwurfsmuster sich einem dieser Merkmale annähern.

Das liegt daran, dass diese Funktionen nicht dieselben Probleme lösen, die OOP ... sie sind Alternativen zur imperativen Programmierung. Die FP Antwort auf OOP liegt in den Typsystemen von ML und Haskell ... insbesondere Summentypen, abstrakte Datentypen, ML-Module, Haskell-Typklassen.

Aber natürlich gibt es immer noch Entwurfsmuster, die nicht durch FP Sprachen gelöst werden. Was ist das FP Äquivalent eines Singletons?) sind in der Regel ein schreckliches Muster zu verwenden)

Die erste Sache, die Typeclasses tun, ist, die Notwendigkeit für Singletons zu beseitigen.

Sie könnten die Liste der 23 durchgehen und mehr eliminieren, aber ich habe momentan keine Zeit dafür.

6
Jason Ganetsky

Ich denke, nur zwei GoF-Designmuster wurden entwickelt, um die Funktionsprogrammierlogik in die natürliche OO Sprache einzuführen. Ich denke über Strategie und Befehl nach. Einige der anderen GoF-Designmuster können durch funktionale Programmierung geändert werden, um das Design zu vereinfachen und den Zweck beizubehalten.

4
CyaNnOrangeHead

Im Wesentlichen ja !

  • Wenn ein Muster die fehlenden Merkmale (Funktionen höherer Ordnung, Stream-Handling ...) umgeht, die ltimativeKomposition erleichtern.
  • Die Notwendigkeit, die Implementierung von Mustern immer wieder neu zu schreiben, kann selbst als Sprachgeruch gesehen werden.

Außerdem bietet diese Seite (AreDesignPatternsMissingLanguageFeatures eine Übersetzungstabelle für Muster/Features und einige nette Diskussionen, wenn Sie bereit sind, zu graben.

4
YvesgereY

OOP und die GoF-Muster befassen sich mit Zuständen. OOP modelliert die Realität, um die Codebasis so nah wie möglich an den gegebenen Anforderungen der Realität zu halten. GoF-Entwurfsmuster sind Muster, die identifiziert wurden, um Probleme der realen Atomwelt zu lösen. Sie behandeln das Problem des Zustands in ein semantischer Weg.

Da in der realen funktionalen Programmierung kein Zustand existiert, ist es nicht sinnvoll, die GoF-Muster anzuwenden. Es gibt keine funktionalen Entwurfsmuster wie GoF-Entwurfsmuster. Jedes funktionale Entwurfsmuster ist im Gegensatz zur Realität künstlich, da Funktionen Konstrukte der Mathematik und nicht der Realität sind.

Funktionen haben kein Zeitkonzept, da sie unabhängig von der aktuellen Zeit immer den gleichen Wert zurückgeben, es sei denn, die Zeit ist Teil der Funktionsparameter, was es wirklich schwierig macht, "zukünftige Anforderungen" zu verarbeiten. Hybride Sprachen mischen diese Konzepte und machen die Sprachen nicht zu echten funktionalen Programmiersprachen.

Funktionale Sprachen nehmen nur wegen einer Sache zu: den gegenwärtigen natürlichen Beschränkungen der Physik. Die Verarbeitungsgeschwindigkeit heutiger Prozessoren ist aufgrund physikalischer Gesetze begrenzt. Sie sehen eine Stagnation der Taktfrequenz, aber eine Ausweitung der Prozessorkerne. Deshalb wird die Parallelität von Anweisungen immer wichtiger, um die Geschwindigkeit moderner Anwendungen zu erhöhen. Da die funktionale Programmierung per Definition keinen Status hat und daher keine Nebenwirkungen hat, ist es sicher, Funktionen sicher parallel zu verarbeiten.

GoF-Muster sind nicht überholt. Sie sind zumindest erforderlich, um die Anforderungen der realen Welt zu modellieren. Wenn Sie jedoch eine funktionierende Programmiersprache verwenden, müssen Sie sie in ihre hybriden Entsprechungen umwandeln. Schließlich haben Sie keine Chance, nur funktionierende Programme zu erstellen, wenn Sie Persistenz verwenden. Für die hybriden Elemente Ihres Programms müssen weiterhin GoF-Muster verwendet werden. Für jedes andere rein funktionale Element ist die Verwendung von GoF-Mustern nicht erforderlich, da kein Status vorhanden ist.

Da die GoF-Muster für eine echte funktionale Programmierung nicht erforderlich sind, bedeutet dies nicht, dass die SOLID Prinzipien nicht angewendet werden sollten. Die SOLID Prinzipien sind über jede Sprache hinaus Paradigma.

3
oopexpert

Im neuen Buch von 2013 mit dem Namen "Functional Programming Patterns - in Scala and Clojure" der Autor Michael.B. Linn macht einen anständigen Job beim Vergleichen und Ersetzen der GoF-Muster in vielen Fällen und erörtert auch die neueren Funktionsmuster wie "Schwanzrekursion", "Memoisierung", "Lazy Sequence" usw.

Dieses Buch ist bei Amazon erhältlich. Ich fand es sehr informativ und ermutigend, wenn ich von einem OO Hintergrund von ein paar Jahrzehnten stammte.

3
manish

Die funktionale Programmierung ersetzt keine Entwurfsmuster. Entwurfsmuster können nicht ersetzt werden.

Muster existieren einfach; Sie entstanden im Laufe der Zeit. Das GoF-Buch hat einige von ihnen formalisiert. Wenn neue Muster auftauchen, während Entwickler funktionale Programmiersprachen verwenden, ist das aufregend, und vielleicht werden auch Bücher darüber geschrieben.

3
ktingle

In der funktionalen Programmierung haben Entwurfsmuster eine andere Bedeutung. In der Tat sind die meisten [~ # ~] oop [~ # ~] Entwurfsmuster in nicht erforderlich Funktionale Programmierung aufgrund der höheren Abstraktionsebene und der Verwendung von HOFs als Bausteine.

Das Prinzip eines HOF bedeutet, dass Funktionen als Argumente an andere Funktionen übergeben werden können. und Funktionen können Werte zurückgeben.

2
Ali Bayat

Ich denke, dass jedes Paradigma einem anderen Zweck dient und als solches nicht auf diese Weise verglichen werden kann.

Ich habe nicht gehört, dass die GoF-Entwurfsmuster für jede Sprache gelten. Ich habe gehört, dass sie für alle OOP-Sprachen gelten. Wenn Sie die Funktionale Programmierung verwenden, unterscheidet sich die Domäne der von Ihnen gelösten Probleme von den Sprachen OO.

Ich würde keine funktionale Sprache verwenden, um eine Benutzeroberfläche zu schreiben, sondern eine der OO Sprachen wie C # oder Java) würde diese Arbeit erleichtern. Wenn ich schreibe Eine funktionale Sprache würde ich dann nicht in Betracht ziehen, OO Design Patterns.

1

Wie die akzeptierte Antwort sagte, haben OOP und FP alle ihre spezifischen Muster.

Es gibt jedoch einige Muster, die so häufig vorkommen, dass ich mir alle Programmierplattformen vorstellen kann. Hier ist eine (unvollständige) Liste:

  • Adapter. Ich kann mir kaum eine nützliche Programmierplattform vorstellen, die so umfassend ist (und sich selbst erfüllt), dass sie nicht mit der Welt sprechen muss. In diesem Fall wird auf jeden Fall ein Adapter benötigt.

  • Fassade. Alle Programmierplattformen, die großen Quellcode verarbeiten können, sollten modularisiert werden können. Wenn Sie ein Modul für andere Teile des Programms erstellen, möchten Sie die "schmutzigen" Teile des Codes ausblenden und ihm eine nette Schnittstelle geben.

  • Dolmetscher. Im Allgemeinen macht jedes Programm nur zwei Dinge: die Eingabe und die Druckausgabe. Mauseingaben müssen analysiert und Fenster-Widgets müssen ausgedruckt werden. Ein eingebetteter Interpreter gibt dem Programm daher zusätzliche Möglichkeiten zum Anpassen.

Außerdem ist mir aufgefallen, dass es in einer typischen FP Sprache, Haskell, etwas gibt, das GoF-Mustern ähnelt, aber unterschiedliche Namen hat. Meiner Meinung nach deutet dies darauf hin, dass sie da waren, weil es einige gemeinsame Probleme gibt, die sowohl in FP als auch in OOP Sprachen zu lösen sind.

  • Monadentransformator und Dekorateur. Ersteres fügt einer vorhandenen Monade zusätzliche Fähigkeiten hinzu, letzteres fügt einem vorhandenen Objekt zusätzliche Fähigkeiten hinzu.
1
Earth Engine

OOP und FP haben unterschiedliche Ziele, OOP soll die Komplexität/Beweglichkeit von Softwarekomponenten zusammenfassen und FP) soll Minimieren Sie die Komplexität und Abhängigkeiten von Softwarekomponenten, aber diese beiden Paradigmen sind nicht unbedingt zu 100% widersprüchlich und können gemeinsam angewendet werden, um den Nutzen beider Welten zu erzielen Wenn Sie die FP Prinzipien verstehen, können Sie OOP Prinzipien auch mit F # anwenden, wenn Sie OOP Prinzipien, Muster und Best Practices: Sie würden die richtige Wahl treffen, basierend auf der Situation und dem Problem, das Sie zu lösen versuchen, unabhängig von der von Ihnen verwendeten Programmiersprache.

1
Dogu Arslan