Ersetzt die funktionale Programmierung die GoF-Entwurfsmuster?

1047

Seit ich letztes Jahr angefangen habe, F # und OCaml zu lernen , habe ich eine Vielzahl von Artikeln gelesen, die darauf bestehen, dass Entwurfsmuster (insbesondere in Java) Problemumgehungen für die fehlenden Funktionen in imperativen Sprachen sind. Ein Artikel, den ich gefunden habe, behauptet ziemlich stark :

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

Funktionssprachen sind äußerst ausdrucksstark. In einer funktionalen Sprache benötigt man keine Entwurfsmuster, da die Sprache wahrscheinlich so hoch ist, dass man am Ende Konzepte programmiert, die Entwurfsmuster insgesamt eliminieren.

Zu den Hauptmerkmalen der funktionalen Programmierung (FP) gehören Funktionen wie erstklassige Werte, Currying, unveränderliche Werte usw. Es scheint mir nicht offensichtlich, dass OO-Entwurfsmuster sich einem dieser Merkmale annähern.

Darüber hinaus scheint es mir in funktionalen Sprachen, die OOP unterstützen (wie F # und OCaml), offensichtlich, dass Programmierer, die diese Sprachen verwenden, dieselben Entwurfsmuster verwenden würden, die für jede andere OOP-Sprache verfügbar sind. Tatsächlich verwende ich momentan 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.

Stimmt die Behauptung, dass durch funktionale Programmierung keine OOP-Entwurfsmuster mehr erforderlich sind? Wenn ja, können Sie ein Beispiel für ein typisches OOP-Entwurfsmuster und dessen funktionales Äquivalent veröffentlichen oder verlinken?

Julia
quelle
18
Sie können den Artikel von Steve Yegge ( steve-yegge.blogspot.com/2006/03/… )
Ralph
27
"Das Buch ist sprachunabhängig und die Muster gelten für das Software-Engineering im Allgemeinen" - es sollte beachtet werden, dass das Buch dieser Behauptung nicht zustimmt, da einige Sprachen bestimmte Dinge wie Entwurfsmuster nicht ausdrücken müssen: "Unsere Muster Nehmen Sie Sprachfunktionen auf Smalltalk / C ++ - Ebene an, und diese Auswahl bestimmt, was einfach implementiert werden kann und was nicht. [...] CLOS verfügt beispielsweise über mehrere Methoden, die die Notwendigkeit eines Musters wie Visitor verringern (Seite 331). " (Seite 4)
Guildenstern
6
Denken Sie auch daran, dass viele Entwurfsmuster in imperativen Sprachen auf ausreichend hohem Niveau nicht einmal erforderlich sind.
R. Barzell
3
@ R.Barzell Was sind diese "ausreichend hohen imperativen Sprachen"? Vielen Dank.
Cibercitizen1
5
@ cibercitizen1 ententypisierte Sprachen mit Unterstützung für Funktionen höherer Ordnung und anonyme Funktionen. Diese Funktionen liefern einen Großteil der Leistung, die viele Entwurfsmuster bieten sollten.
R. Barzell

Antworten:

1077

Der Blog-Beitrag, den Sie zitiert haben, übertreibt seine Behauptung ein wenig. FP nicht beseitigt die Notwendigkeit für Design - Muster. Der Begriff "Entwurfsmuster" wird in FP-Sprachen nicht häufig verwendet, um dasselbe zu beschreiben. Aber sie existieren. Funktionale Sprachen haben viele Best-Practice-Regeln der Form "Wenn Sie auf Problem X stoßen, verwenden Sie Code, der wie Y aussieht", was im Grunde ein Entwurfsmuster ist.

Es ist jedoch richtig, dass die meisten OOP-spezifischen Entwurfsmuster in funktionalen Sprachen so gut wie irrelevant sind.

Ich denke nicht, dass es besonders kontrovers sein sollte zu sagen, dass Designmuster im Allgemeinen nur existieren, um Mängel in der Sprache zu beheben. Und wenn eine andere Sprache das gleiche Problem trivial lösen kann, benötigt diese andere Sprache kein Entwurfsmuster dafür. Benutzer dieser Sprache sind sich möglicherweise nicht einmal bewusst, dass das Problem besteht , da es in dieser Sprache kein Problem darstellt.

Folgendes sagt die Viererbande zu diesem Thema:

Die Wahl der Programmiersprache ist wichtig, da sie den eigenen Standpunkt beeinflusst. Unsere Muster setzen Sprachfunktionen auf Smalltalk / C ++ - Ebene voraus, und diese Auswahl bestimmt, was einfach implementiert werden kann und was nicht. Wenn wir prozedurale Sprachen angenommen hätten, hätten wir möglicherweise Entwurfsmuster mit den Namen "Vererbung", "Kapselung" und "Polymorphismus" aufgenommen. In ähnlicher Weise werden einige unserer Muster direkt von den weniger verbreiteten objektorientierten Sprachen unterstützt. CLOS verfügt beispielsweise über mehrere Methoden, die die Notwendigkeit eines Musters wie "Besucher" verringern. Tatsächlich gibt es genug Unterschiede zwischen Smalltalk und C ++, um zu bedeuten, dass einige Muster in einer Sprache leichter ausgedrückt werden können als in der anderen. (Siehe zum Beispiel Iterator.)

(Das Obige ist ein Zitat aus dem Buch Einführung in das Entwurfsmuster, Seite 4, Absatz 3)

Zu den Hauptmerkmalen der funktionalen Programmierung gehören Funktionen wie erstklassige Werte, Currying, unveränderliche Werte usw. Es scheint mir nicht offensichtlich, dass OO-Entwurfsmuster sich einem dieser Merkmale annähern.

Was ist das Befehlsmuster, wenn nicht eine Annäherung an erstklassige Funktionen? :) In einer FP-Sprache würden Sie einfach eine Funktion als Argument an eine andere Funktion übergeben. In einer OOP-Sprache müssen Sie die Funktion in eine Klasse einschließen, die Sie instanziieren und dann an die andere Funktion übergeben können. Der Effekt ist der gleiche, aber in OOP wird er als Entwurfsmuster bezeichnet, und es wird viel mehr Code benötigt. Und was ist das abstrakte Fabrikmuster, wenn nicht Curry? Übergeben Sie die Parameter nach und nach an eine Funktion, um zu konfigurieren, welche Art von Wert ausgegeben wird, wenn Sie sie schließlich aufrufen.

Ja, mehrere GoF-Entwurfsmuster werden in FP-Sprachen überflüssig, da leistungsfähigere und benutzerfreundlichere Alternativen existieren.

Aber natürlich gibt es immer noch Entwurfsmuster, die von FP-Sprachen nicht gelöst werden. Was ist das FP-Äquivalent eines Singletons? (Ignorieren Sie für einen Moment, dass Singletons im Allgemeinen ein schreckliches Muster sind.)

Und es funktioniert auch in beide Richtungen. Wie gesagt, FP hat auch seine Designmuster; Leute denken normalerweise einfach nicht an sie als solche.

Aber Sie sind vielleicht auf Monaden gestoßen. Was sind sie, wenn nicht ein Entwurfsmuster für den "Umgang mit dem globalen Staat"? Das ist ein Problem, das in OOP-Sprachen so einfach ist, dass dort kein gleichwertiges Entwurfsmuster existiert.

Wir benötigen kein Entwurfsmuster für "Inkrementieren einer statischen Variablen" oder "Lesen aus diesem Socket", da dies genau das ist, was Sie tun .

Zu sagen, eine Monade sei ein Entwurfsmuster, ist genauso absurd wie zu sagen, dass die Ganzzahlen mit ihren üblichen Operationen und das Nullelement ein Entwurfsmuster sind. Nein, eine Monade ist ein mathematisches Muster , kein Entwurfsmuster.

In (reinen) funktionalen Sprachen sind Nebenwirkungen und veränderlicher Zustand unmöglich, es sei denn, Sie umgehen dies mit dem Monaden- "Entwurfsmuster" oder einer der anderen Methoden, um dasselbe zuzulassen.

Darüber hinaus scheint es mir in funktionalen Sprachen, die OOP unterstützen (wie F # und OCaml), offensichtlich, dass Programmierer, die diese Sprachen verwenden, dieselben Entwurfsmuster verwenden würden, die für jede andere OOP-Sprache verfügbar sind. Tatsächlich verwende ich momentan 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.

Vielleicht, weil Sie immer noch zwingend denken? Viele Menschen haben es schwer, diese Gewohnheit aufzugeben, wenn sie eine funktionierende Sprache ausprobieren, nachdem sie sich ihr ganzes Leben lang mit imperativen Sprachen beschäftigt haben. (Ich habe einige ziemlich lustige Versuche mit F # gesehen, bei denen buchstäblich jede Funktion nur eine Folge von 'let'-Anweisungen war, im Grunde genommen, als hätten Sie ein C-Programm genommen und alle Semikolons durch' let 'ersetzt. :))

Eine andere Möglichkeit könnte sein, dass Sie einfach nicht bemerkt haben, dass Sie Probleme trivial lösen, die Entwurfsmuster in einer OOP-Sprache erfordern würden.

Wenn Sie Curry verwenden oder eine Funktion als Argument an eine andere übergeben, halten Sie inne und überlegen Sie, wie Sie dies in einer OOP-Sprache tun würden.

Stimmt die Behauptung, dass durch funktionale Programmierung keine OOP-Entwurfsmuster mehr erforderlich sind?

Ja. :) Wenn Sie in einer FP-Sprache arbeiten, benötigen Sie die OOP-spezifischen Entwurfsmuster nicht mehr. Sie benötigen jedoch noch einige allgemeine Entwurfsmuster wie MVC oder andere nicht OOP-spezifische Dinge, und Sie benötigen stattdessen einige neue FP-spezifische "Entwurfsmuster". Alle Sprachen haben ihre Mängel, und Designmuster sind normalerweise die Art und Weise, wie wir sie umgehen.

Wie auch immer, Sie finden es vielleicht interessant, sich in "saubereren" FP-Sprachen wie ML (mein persönlicher Favorit, zumindest zu Lernzwecken) oder Haskell zu versuchen , wo Sie nicht über die OOP-Krücke verfügen, auf die Sie zurückgreifen können, wenn Sie darauf zurückgreifen Ich bin mit etwas Neuem konfrontiert.


Wie erwartet haben einige Leute Einwände gegen meine Definition von Designmustern als "Ausbessern von Mängeln in einer Sprache" erhoben. Hier ist meine Rechtfertigung:

Wie bereits gesagt, sind die meisten Entwurfsmuster spezifisch für ein Programmierparadigma oder manchmal sogar für eine bestimmte Sprache. Oft sie Probleme lösen , die nur existieren in diesem Paradigma (Monaden für FP, oder abstrakte Fabriken für OOP sehen).

Warum existiert das abstrakte Fabrikmuster in FP nicht? Weil das Problem, das es zu lösen versucht, dort nicht existiert.

Wenn also ein Problem in OOP-Sprachen besteht, das in FP-Sprachen nicht vorhanden ist, ist dies eindeutig ein Mangel an OOP-Sprachen. Das Problem kann gelöst werden, aber Ihre Sprache tut dies nicht, sondern erfordert eine Menge Boilerplate-Code von Ihnen, um es zu umgehen. Idealerweise möchten wir, dass unsere Programmiersprache alle Probleme auf magische Weise beseitigt. Jedes Problem, das noch besteht, ist im Prinzip ein Mangel der Sprache. ;)

jalf
quelle
73
Entwurfsmuster beschreiben allgemeine Lösungen für grundlegende Probleme. Aber genau das tun auch Programmiersprachen und Plattformen. Sie verwenden also Entwurfsmuster, wenn die von Ihnen verwendeten Sprachen und Plattformen nicht ausreichen.
Yfeldblum
135
S.Lott: Sie beschreiben Lösungen für Probleme, die in einer bestimmten Sprache existieren, ja. In FP-Sprachen gibt es kein Befehlsentwurfsmuster, da das zu lösende Problem nicht vorhanden ist. Das bedeutet, dass sie Probleme lösen, die die Sprache selbst nicht lösen kann. Das heißt, Mängel in der Sprache
Jalf
38
Die Monade ist ein mathematisches Konzept, und Sie erweitern es mit Ihrer Klassifizierung. Natürlich können Sie Funktionen, Monoide, Monaden, Matrizen oder andere mathematische Konzepte als Entwurfsmuster anzeigen, aber diese ähneln eher Algorithmen und Datenstrukturen ... grundlegende Konzepte, sprachunabhängig.
Alexandru Nedelcu
41
Sicher, Monaden sind ein mathematisches Konzept, aber sie sind auch ein Muster. Das "FP-Muster" von Monaden unterscheidet sich etwas vom mathematischen Konzept von Monaden. Ersteres ist ein Muster, das verwendet wird, um bestimmte "Einschränkungen" in reinen FP-Sprachen zu umgehen. Letzteres ist ein universelles mathematisches Konzept.
Jalf
69
Beachten Sie, dass Monaden in Haskell für andere Zwecke als den veränderlichen Status verwendet werden, z. B. für Ausnahmen, Fortsetzungen, Listenverständnisse, Parsen, asynchrone Programmierung usw. Aber all diese Anwendungen von Monaden könnten wahrscheinlich als Muster bezeichnet werden.
JacquesB
152

Stimmt die Behauptung, dass durch funktionale Programmierung keine OOP-Entwurfsmuster mehr erforderlich sind?

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

Für die funktionale Programmierung werden Sie die OO-Entwurfsmusterbücher nicht lesen. Sie werden andere Bücher über FP-Designmuster lesen.

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 Datenbankdesignkontext kaum sinnvoll. Sie gelten nicht beim Entwerfen einer Tabelle.

ein typisches OOP-Entwurfsmuster und sein funktionales Äquivalent?

Das obige sollte nicht existieren. Das ist so, als würde man nach einem prozeduralen Code fragen, der als OO-Code umgeschrieben wurde. Ummm ... Wenn ich das ursprüngliche Fortran (oder C) in Java übersetze, habe ich nichts weiter getan, als es zu übersetzen. Wenn ich es komplett in ein OO-Paradigma umschreibe, sieht es nicht mehr wie das ursprüngliche Fortran oder C aus - es ist nicht wiederzuerkennen.

Es gibt keine einfache Zuordnung vom OO-Design zum funktionalen Design. Sie sehen das Problem sehr unterschiedlich.

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

Entwurfsmuster - als Konzept - sind eine zeitlose Art zu bauen, unabhängig von Technologie oder Problembereich. Bestimmte Entwurfsmuster gelten jedoch für bestimmte Problembereiche und Technologien.

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

S.Lott
quelle
12
MVC ist kein OO-Design. Es ist architektonisches Design - dieses Muster ist ziemlich weit verbreitet.
S.Lott
1
@Princess: Funktionale Programmierung ist nicht unbedingt einfacher. In Ihrem Beispiel ja. Für andere Dinge ist die Jury immer noch nicht da. Sie haben jedoch ein Java OO-Entwurfsmuster verworfen und ein FP-Entwurfsmuster übernommen.
S.Lott
1
+1: Ich ziehe diese Antwort der obigen Antwort von Jalf vor. Obwohl einige Entwurfsmuster Mängel in der Sprache beheben, tun dies nicht alle. Zum Beispiel würde ich kaum sagen, dass das Entwurfsmuster "Lösen des rekursiven Knotens" einen Sprachmangel behebt. Es ist nur eine nützliche Redewendung, um Abhängigkeiten zu lösen.
Jon Harrop
9
Java 8 enthält Verschlüsse, auch bekannt als anonyme Funktionen, auch bekannt als Lambda-Ausdrücke. Dadurch wird das Befehlsentwurfsmuster für Java veraltet. Dies ist ein Beispiel für einen Sprachmangel, nicht wahr? Sie haben eine fehlende Funktion hinzugefügt, und jetzt benötigen Sie das Entwurfsmuster nicht mehr.
Todd Chaffee
2
+1 für den Schlusssatz. Entwurfsmuster sollen die Programmierung vereinfachen und die resultierenden Programme effizienter machen, je nachdem, was sie tun sollen.
Sortierer
46

Brians Kommentare zur engen Verbindung zwischen Sprache und Muster sind auf den Punkt gebracht,

Der fehlende Teil dieser Diskussion ist das Konzept der Redewendung. James O. Copliens Buch "Advanced C ++" war hier ein großer Einfluss. Lange bevor er Christopher Alexander und die Spalte ohne Namen entdeckte (und man kann auch nicht vernünftig über Muster sprechen, ohne Alexander zu lesen), sprach er darüber, wie wichtig es ist, Redewendungen zu beherrschen, um wirklich eine Sprache zu lernen. Er hat die Zeichenfolgenkopie in C als Beispiel verwendet. 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 eine größere Einheit des Denkens oder Ausdrucks ist als irgendeines von seine Teile.

Das ist es, was Muster und Sprachen versuchen, damit wir unsere Absichten prägnanter ausdrücken können. Je reicher die Gedankeneinheiten sind, desto komplexer sind die Gedanken, die Sie ausdrücken können. Ein reichhaltiges, gemeinsames Vokabular in verschiedenen Maßstäben - von der Systemarchitektur bis hin zum Twiddling - ermöglicht uns intelligentere Gespräche und Gedanken darüber, 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, an die wir niemals denken könnten. Sprachen, Frameworks, Bibliotheken, Muster, Redewendungen usw. haben ihren Platz darin, den geistigen Reichtum zu teilen.

Peter Mortensen
quelle
8
Vielen Dank! Darum geht es bei Mustern - "konzeptionelles Chunking", um die kognitive Belastung zu senken.
Randall Schulz
Und funktionale Monaden gehören definitiv in diese Diskussion.
Greg
@RandallSchulz: Sprachfunktionen (und natürlich ihre idiomatische Verwendung) würden auch gut in die Kategorie "konzeptionelles Chunking zur Verringerung der kognitiven Belastung" passen.
Roy Tinker
39

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

hell
quelle
26

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.

Folone
quelle
4
Der Artikel scheint nicht wirklich Designmuster in Haskell zu zeigen, sondern zeigt, wie Haskell diese Anforderungen ohne diese Muster erfüllt.
Fresheyeball
3
@Fresheyball: Hängt von Ihrer Definition von Mustern ab. Ist das Zuordnen einer Funktion über eine Liste eine Variante des Besuchermusters? Ich habe allgemein gedacht, dass die Antwort "Ja" war. Muster sollen über eine bestimmte Syntax hinausgehen. Die angewendete Funktion könnte als Objekt verpackt oder als Funktionszeiger übergeben werden, aber das Konzept ist für mich dasselbe. Stimmen Sie nicht zu?
srm
20

Wenn Sie versuchen, dies auf der Ebene der "Entwurfsmuster" (im Allgemeinen) und "FP versus OOP" zu betrachten, werden die Antworten, die Sie finden, bestenfalls trübe sein.

Gehen Sie jedoch auf beiden Achsen eine Ebene tiefer und berücksichtigen Sie bestimmte Entwurfsmuster und bestimmte Sprachmerkmale, und die Dinge werden klarer.

So ändern oder verschwinden beispielsweise bestimmte Muster wie Besucher , Strategie , Befehl und Beobachter definitiv, wenn eine Sprache mit algebraischen Datentypen und Mustervergleich , Abschlüssen , erstklassigen Funktionen usw. verwendet wird. Einige andere Muster aus dem GoF-Buch sind noch vorhanden "Bleib dabei".

Im Allgemeinen würde ich sagen, dass im Laufe der Zeit bestimmte Muster durch neue (oder nur immer beliebter werdende) Sprachfunktionen beseitigt werden. Dies ist der natürliche Verlauf des Sprachdesigns. Wenn Sprachen immer höher werden, werden Abstraktionen, die bisher nur in einem Buch anhand von Beispielen aufgerufen werden konnten, jetzt zu Anwendungen eines bestimmten Sprachmerkmals oder einer bestimmten Bibliothek.

(Nebenbei: Hier ist ein kürzlich von mir geschriebener Blog , der weitere Links zu weiteren Diskussionen über FP und Entwurfsmuster enthält.)

Brian
quelle
Wie kann man sagen, dass das Besuchermuster "verschwindet"? Wird nicht einfach von "Erstellen einer Besucherschnittstelle mit einer Reihe von Besuchsmethoden" zu "Verwenden von Vereinigungstypen und Mustervergleich"?
Gabe
22
Ja, aber das hat sich von einem Muster, das eine Designidee ist, über die Sie in einem Buch gelesen und auf Ihren Code angewendet haben, zu "nur Code" geändert . Das heißt, "Vereinigungstypen und Mustervergleich verwenden" ist genau das, was Sie normalerweise in einer solchen Sprache codieren. (Analogie: Wenn keine Sprachen forSchleifen hatten und alle nur whileSchleifen hatten, könnte "For" ein Iterationsmuster sein. Aber wenn fornur ein Konstrukt von der Sprache unterstützt wird und wie Menschen normal codieren, dann ist es kein Muster - Sie tun es nicht. Ich brauche kein Muster, es ist nur Code, Mann.)
Brian
4
Anders ausgedrückt, ein vielleicht nicht schlechter Lackmustest für "Ist es ein Muster" lautet: Präsentieren Sie den Code, der auf diese Weise geschrieben wurde, für einen Studenten im zweiten Studienjahr mit Schwerpunkt CS mit einem Jahr Erfahrung in der Programmierung in Ihrer Sprache. Wenn Sie ihnen den Code zeigen und sie sagen "das ist ein cleveres Design", dann ist es ein Muster. Wenn Sie ihnen den Code zeigen und sie "gut, duh!" Sagen, dann ist es kein Muster. (Und wenn Sie diesen "Besucher" jedem zeigen, der ML / F # / Haskell für ein Jahr gemacht hat, werden sie "gut, duh!" Gehen)
Brian
1
Brian: Ich denke, wir haben nur unterschiedliche Definitionen eines "Musters". Ich betrachte jede identifizierbare Designabstraktion als Muster , während Sie nur nicht offensichtliche Abstraktionen als Muster betrachten . Nur weil C # foreachund Haskell haben, mapMheißt das nicht, dass sie nicht das Iteratormuster haben. Ich sehe kein Problem darin zu sagen, dass das Iterator-Muster als generische Schnittstelle IEnumerable<T>in C # und als Typklasse Traversablein Haskell implementiert ist .
Gabe
Es kann sein, dass nicht offensichtliche Muster für Softwareentwickler von Nutzen sind, aber alle Muster für Sprachdesigner von Nutzen sind. Dh "Wenn Sie eine neue Sprache erstellen, stellen Sie sicher, dass Sie eine saubere Methode zum Ausdrücken des Iteratormusters angeben." Sogar die offensichtlichen Muster sind von Interesse, wenn wir die Frage stellen: "Gibt es eine bessere Syntax, um diese Idee auszudrücken?" Schließlich hat das jemanden dazu gebracht, foreach zu erstellen.
srm
16

Norvigs Präsentation spielt auf eine Analyse aller GoF-Muster an und sagt, dass 16 der 23 Muster einfachere Implementierungen in funktionalen Sprachen hatten oder einfach Teil der Sprache waren. Vermutlich waren mindestens sieben von ihnen entweder a) gleich kompliziert oder b) nicht in der Sprache vorhanden. Leider sind sie für uns 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 ++ dazu zu bringen, das zu tun, was Sie wollen. Aber der Rest ist eine Überlegung wert, egal in welcher Sprache Sie programmieren.

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

Eines meiner Lieblingsmuster ist das Nullobjektmuster: Stellen Sie das Fehlen von etwas als Objekt dar, das eine angemessene Art von Nichts tut. Dies ist möglicherweise einfacher in einer funktionalen Sprache zu modellieren. Die eigentliche Errungenschaft ist jedoch der Perspektivwechsel.

Peter Mortensen
quelle
2
Was für eine seltsame Analyse, da die GoF-Muster speziell für klassenbasierte OOP-Sprachen entwickelt wurden. Scheint ein bisschen wie zu analysieren, ob Rohrzangen für elektrische Arbeiten gut sind.
Munificent
@ Munificent: Nicht wirklich. Objektorientierung sorgt für Polymorphismus; funktionale Programmierung liefert im Allgemeinen Polymorphismus.
Marcin
@Marcin Ein OO-Programmierer bedeutet durch Polymorphismus etwas ganz anderes als ein funktionaler Programmierer.
AndrewC
@ AndrewC Ich bin anderer Meinung. Der OO-Programmierer mag denken, dass sie etwas anderes bedeuten, aber sie tun es nicht.
Marcin
3
@Marcin Nach meiner Erfahrung bezieht sich ein OO-Programmierer normalerweise auf den Subtyp-Polymorphismus (häufig nur unter Verwendung von Object), die Verwendung von Casts, um dies zu erreichen, oder auf den Ad-hoc-Polymorphismus (Überladung usw.). Wenn ein funktionaler Programmierer Polymorphismus sagt, bedeutet dies parametrischen Polymorphismus (dh funktioniert für jede Art von Daten - Int, Funktion, Liste), der möglicherweise eher der generischen Programmierung von OO ähnelt als dem, was OO-Programmierer normalerweise Polymorphismus nennen.
AndrewC
15

Ich würde sagen, wenn Sie eine Sprache wie Lisp mit Unterstützung für Makros haben, können Sie Ihre eigenen domänenspezifischen Abstraktionen erstellen, Abstraktionen, die oft viel besser sind als die allgemeinen Redewendungen.

Anders Rune Jensen
quelle
Ich bin völlig verloren. Etwas mit Abstraktionen aufpeppen ... Was bedeutet das?
Tuinstoel
2
Sie können domänenspezifische Abstraktionen (auch eingebettete) ohne Makros erstellen. Mit Makros können Sie sie nur durch Hinzufügen einer benutzerdefinierten Syntax aufpeppen.
Jon Harrop
2
Sie können sich Lisp als eine Reihe von Legos zum Erstellen von Programmiersprachen vorstellen - es ist eine Sprache, aber es ist auch eine Metasprache. Dies bedeutet, dass Sie für jede Problemdomäne eine Sprache individuell gestalten können, die keine offensichtlichen Mängel aufweist. Es wird etwas Übung erfordern, und Kurt Gödel mag anderer Meinung sein, aber es lohnt sich, einige Zeit mit Lisp zu verbringen, um zu sehen, was es auf den Tisch bringt (Hinweis, Makros).
Greg
9

Und selbst die OO-Entwurfsmusterlösungen sind sprachspezifisch.

Entwurfsmuster sind Lösungen für häufig auftretende Probleme, die Ihre Programmiersprache für Sie nicht löst. In Java löst das Singleton-Muster das (vereinfachte) Problem.

In Scala haben Sie zusätzlich zu Class ein Konstrukt der obersten Ebene namens Object. Es ist träge instanziiert und es gibt nur eine. Sie müssen das Singleton-Muster nicht verwenden, um einen Singleton zu erhalten. Es ist Teil der Sprache.

Peter Mortensen
quelle
8

Muster sind Möglichkeiten, ähnliche Probleme zu lösen, die immer wieder auftreten und dann beschrieben und dokumentiert werden. Also nein, FP wird Muster nicht ersetzen. FP kann jedoch neue Muster erstellen und einige aktuelle "Best Practices" -Muster "obsolet" machen.

Edwin Buck
quelle
4
GoP-Muster sind Möglichkeiten, um das Problem der Einschränkungen einer bestimmten Art von Programmiersprache zu lösen, die Ihnen im Weg stehen. Zum Beispiel "Ich möchte Klassen indirekt behandeln und ihnen sagen, dass sie Objekte erstellen sollen" -> "Sie können nicht, aber Sie können metaklassenähnliche Objekte erstellen, die als Factory bezeichnet werden". "Ich möchte Mehrfachversand" -> "Sie können nicht, aber es gibt ein Labyrinth, das Sie implementieren können, das Besuchermuster". Keines der Muster ist sinnvoll, wenn Sie nicht in einer OOP-Sprache mit bestimmten Einschränkungen sind.
Kaz
1
Ich weiß nicht, dass "keiner" in anderen Sprachen Sinn macht, aber ich stimme zu, dass viele von ihnen in anderen Sprachen keinen Sinn ergeben. Adapter und Bridge scheinen mehr mehrsprachige Möglichkeiten zu haben, die für Besucher etwas abnehmen und für Hörer vielleicht etwas weniger. Sprachübergreifende Muster leiden jedoch immer unter dem Typ "Wie wird die Operation von Sprache X in Sprache Y ausgeführt?", Der die natürlichen Grenzen der Sprache stützt. Ein perfektes Beispiel war das Singleton-Muster. Wie bekomme ich C-Globale in OOP? (was ich antworten werde, solltest du nicht).
Edwin Buck
1
Ich zweite Kaz: Muster sind nicht "eine Möglichkeit, ähnliche Probleme zu lösen, die immer wieder gesehen werden", sondern "eine Art, ähnliche Probleme zu lösen, die immer wieder gesehen werden UND müssen immer wieder neu geschrieben werden, weil die Sprache dies nicht zulässt schreibe es nur einmal ". Mit anderen Worten, wenn die Sprache das Extrahieren / Abstrahieren des Musters in Bibliothek / Klasse / Modul usw. zuließ, ist es kein Muster mehr, sondern wird zu einer Bibliothek / Klasse / Modul. In FP ist es viel einfacher, Codebits in eine Funktion zu extrahieren / zu abstrahieren, daher lassen sich "Muster" leichter in wiederverwendbaren Code konvertieren, sodass sie kein Muster sind.
mb14
1
Ihre Interpretation ist willkommen, aber das GoF-Buch war klar, ein Muster zu definieren, und wenn Sie die einleitenden Kapitel lesen, sagt es nichts über Sprachen oder Schwächen der Sprache aus. Sicherlich haben einige Sprachen Bereiche, in denen sie einige Muster häufiger nutzen, aber ob Sie sie zehnmal schreiben (ausschneiden und einfügen) oder einmal mit zehn Realisierungen implementieren (Unterklassifizierung) oder ein Framework konfigurieren, das zehnmal leicht ausgeführt wird Auf verschiedene Weise wird nur ein Implementierungsdetail des Musters angezeigt.
Edwin Buck
1
Wenn ich nach Jahren wieder in dieses Gespräch zurückkomme, denke ich, dass viele Leute Patterns mit einer bestimmten Programmiersprache oder einem bestimmten Programmierparadigma assoziieren. Sie können in einem solchen Kontext verwendet werden, existierten jedoch vor der Programmierung. "Eine zeitlose Art zu bauen" diskutiert Muster in der Gebäudearchitektur und in der Gemeindeplanung. Dies impliziert, dass die musterorientierten Techniken außerhalb der "Einschränkungen einer Sprache" verwendet werden können, es sei denn, Sie möchten die Gebäudekonstruktion als Programmiersprache bezeichnen :)
Edwin Buck
8

Wie andere gesagt haben, gibt es Muster, die für die funktionale Programmierung spezifisch sind. Ich denke, das Problem, Designmuster loszuwerden, ist nicht so sehr eine Frage der Umstellung auf funktionale, sondern eine Frage der Sprachmerkmale .

Schauen Sie sich an, wie Scala das "Singleton-Muster" beseitigt: Sie deklarieren einfach ein Objekt anstelle einer Klasse. Ein weiteres Merkmal, der Mustervergleich, hilft dabei, die Unbeholfenheit des Besuchermusters zu vermeiden. Sehen Sie den Vergleich hier: Scalas Pattern Matching = Besuchermuster auf Steroiden

Und Scala ist wie F # eine Fusion von OO-Funktionen. Ich weiß nichts über F #, aber es hat wahrscheinlich diese Art von Funktionen.

Verschlüsse sind in funktionaler Sprache vorhanden, müssen aber nicht auf sie beschränkt sein. Sie helfen beim Delegatormuster.

Noch eine Beobachtung. Dieser Code implementiert ein Muster: Es ist so ein Klassiker 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 ein im Wesentlichen funktionales Konstrukt übernommen, um damit umzugehen: "foreach".

Deutsche
quelle
Ich würde sagen, dass Scala erstklassige Unterstützung für das Singleton-Muster bietet. Das Muster ist noch vorhanden, aber der zum Anwenden des Musters erforderliche Boilerplate-Code ist im Vergleich zu Java stark reduziert.
JacquesB
Wenn Meinungen wie ein ******* waren, na ja ... Schauen Sie sich den Rest der Antworten an. "Sie deklarieren einfach ein Objekt anstelle einer Klasse" ist so wahr, dass ich es explizit als Objektliteral bezeichnen würde (dh var singleton = {};). Ich mag auch die Erwähnung über das foreach-Muster. Leider scheinen die meisten Leute, die diese Frage beantwortet / kommentiert haben, die funktionale Programmierung nicht zu verstehen und würden lieber die Verwendung von OOP-Entwurfsmustern rechtfertigen. +1 für konkrete Beispiele würde ich mehr geben, wenn ich könnte.
Evan Plaice
@JacquesB Ich kann Scala / Haskell nicht kommentieren, aber in JavaScript (dh Hybridfunktional / Imperativ) gibt es absolut kein Boilerplate. Sie passen einfach die Art und Weise an, wie Sie Objekte deklarieren, indem Sie Kombinationen aus Objektliteral-Syntax, anonymen Funktionen und Funktionen als Erstes verwenden Klassenmitglieder und Ermöglichen einer Mehrfachvererbung (wodurch die Notwendigkeit von Schnittstellenverträgen entfällt).
Evan Plaice
8

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

Die meisten der durch die Entwurfsmuster behandelten "Übel" werden verursacht durch:

  • statisch typisierte Klassen, die Objekte angeben, aber selbst keine Objekte sind;
  • Beschränkung auf Einzelversand (nur das Argument ganz links wird zur Auswahl einer Methode verwendet, die übrigen Argumente werden nur als statische Typen betrachtet: Wenn sie dynamische Typen haben, liegt es an der Methode, dies mit Ad-hoc-Ansätzen zu klären);
  • Unterscheidung zwischen regulären Funktionsaufrufen und objektorientierten Funktionsaufrufen, was bedeutet, dass objektorientierte Funktionen nicht als funktionale Argumente ü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 so strukturiert ist wie im entsprechenden Entwurfsmuster. (Darüber hinaus geht dieses Objektsystem dem GoF-Buch weit über ein Jahrzehnt voraus. Common Lisp wurde im selben Jahr, in dem dieses Buch erstmals veröffentlicht wurde, zum ANSI-Standard.)

Was die funktionale Programmierung betrifft, hängt es davon ab, ob die gegebene funktionale Programmiersprache eine Art Objektsystem hat 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 vorne und in der Mitte liegt.

Konstruktion und nicht mutierender Zugriff sind mit funktionaler Programmierung kompatibel. Daher können Muster angewendet werden, die mit abstrahiertem Zugriff oder Konstruktion zu tun haben: Muster wie Factory, Facade, Proxy, Decorator und Visitor.

Andererseits gelten Verhaltensmuster wie Zustand und Strategie wahrscheinlich nicht direkt für die funktionale OOP, da die Mutation des Zustands in ihrem Kern liegt. Dies bedeutet nicht, dass sie nicht zutreffen. Vielleicht lassen sie sich irgendwie in Kombination mit den verfügbaren Tricks anwenden, um einen veränderlichen Zustand zu simulieren.

Kaz
quelle
2
"Die GoF-Entwurfsmuster codieren Umgehungsrezepte" ist einfach eine falsche Aussage.
John Peters
7

Ich möchte ein paar ausgezeichnete, aber etwas dichte Artikel von Jeremy Gibbons einfügen: "Entwurfsmuster als generische Datentypprogramme höherer Ordnung" und "Die Essenz des Iteratormusters" (beide hier verfügbar: http: // www. comlab.ox.ac.uk/jeremy.gibbons/publications/ ).

Beide beschreiben, wie idiomatische Funktionskonstrukte das Gelände abdecken, das von bestimmten Entwurfsmustern in anderen (objektorientierten) Einstellungen abgedeckt wird.

sclv
quelle
6

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

Zu den Hauptmerkmalen der funktionalen Programmierung gehören Funktionen wie erstklassige Werte, Currying, unveränderliche Werte usw. Es scheint mir nicht offensichtlich, dass OO-Entwurfsmuster sich einem dieser Merkmale annähern.

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

Aber natürlich gibt es immer noch Entwurfsmuster, die von FP-Sprachen nicht gelöst werden. Was ist das FP-Äquivalent eines Singletons? (Ignorieren Sie für einen Moment, dass Singletons im Allgemeinen ein schreckliches Muster sind)

Das erste, was Typklassen tun, ist die Notwendigkeit von Singletons zu beseitigen.

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

Jason Ganetsky
quelle
6
Wie eliminieren Typklassen (das FP-Äquivalent von OOP-Schnittstellen) die Notwendigkeit von Singletons (das FP-Äquivalent des globalen Zustands)?
Gabe
4

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

CyaNnOrangeHead
quelle
4
Das Hauptziel vieler Muster ist es, den Polymorphismus zu nutzen, um Dinge zu tun, die eine angemessene Unterstützung für FP-Konzepte automatisch ermöglichen könnte. (Die meisten Inkarnationen, die ich zum Beispiel von Builder gesehen habe, sind nur halbherziges Currying.) Sobald Sie Funktionen einfach als Werte behandeln können, vereinfachen sich Muster oft bis zur Trivialität. Sie werden zu "Rückruf übergeben" oder "haben ein Wörterbuch mit Rückrufen" - und verschiedene Builder-Klassen können beispielsweise so gut wie verschwinden. IMO ein Muster hört auf, ein Muster zu sein, sobald es trivial genug ist, um genau zu sein, wie die Dinge funktionieren , und nicht etwas, das Sie implementieren müssen.
CHao
3

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 zutage treten, wenn Entwickler funktionale Programmiersprachen verwenden, ist das aufregend, und vielleicht werden auch Bücher darüber geschrieben.

ktingle
quelle
1
Designmuster können nicht ersetzt werden? Das ist ein bisschen verschlossen, denke ich. Wir können uns wahrscheinlich alle einig sein, dass Entwurfsmuster Programmierprobleme lösen sollen, und ich möchte zumindest hoffen, dass wir diese Probleme eines Tages ohne Entwurfsmuster lösen können.
Metropolis
3
Ein bestimmtes Muster kann ersetzt werden, das Konzept der Muster jedoch nicht. Denken Sie daran, dass der Begriff "Muster" im Bereich der Architektur entstanden ist .
Frank Shearar
1
Muster sollen keine Programmierprobleme lösen. Muster sind Wege, wie wir programmieren. Die Dokumentation von Mustern soll helfen, Programmierprobleme zu lösen.
Torbjørn
3
@ Torbjørn: Muster sind Wege, die wir programmieren, wenn die Sprache im Weg ist . Sie bestehen aufgrund einer gewissen Nichtübereinstimmung zwischen dem gewünschten Verhalten des Programms und den integrierten Fähigkeiten der Sprache, bei denen die Anforderungen und Fähigkeiten nicht gut oder nicht eindeutig zugeordnet sind. Ohne das gäbe es kein Muster. Sie hätten eine Implementierung, mit der die Dinge genau so gemacht werden , und andere Implementierungen wären effektiv keine Überlegung wert.
CHao
1
Nur dass Muster wirklich nur existieren, um die Kommunikation zu erleichtern. Es gibt keinen anderen Zweck. Und in all den Design-Meetings, an denen ich im Laufe der Jahre teilgenommen habe, war eine Diskussion des Algorithmus wichtig, nicht das Muster. Das Muster erklärte selten, was wirklich in einem sinnvollen Sinne vor sich ging. Erklärt es genau die Auswirkungen von O (n) gegen O (n Log (n))? Erklärt es, wie einfach es in die vorhandene Architektur passt? Nein, vollständige Algorithmusdiskussionen. Ich argumentiere nicht, dass Muster per se zurückgezogen werden sollten, aber wenn sie es wären, würde fast nichts darunter leiden.
3

In dem neuen Buch von 2013 mit dem Titel "Functional Programming Patterns- in Scala and Clojure" hat der Autor Michael.B. Linn leistet gute Arbeit beim Vergleichen und Ersetzen der GoF-Muster in vielen Fällen und diskutiert 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 aus einem OO-Hintergrund von ein paar Jahrzehnten stamme.

manisch
quelle
3

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 atomare Probleme der realen Welt zu lösen. Sie behandeln das Problem des Staates semantisch.

Da in der realen Funktionsprogrammierung 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 fehlt das Konzept der Zeit, 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 aufgrund einer Sache zu: der gegenwärtigen natürlichen Einschränkungen der Physik. Heutzutage sind Prozessoren aufgrund physikalischer Gesetze in ihrer Verarbeitungsgeschwindigkeit begrenzt. Sie sehen eine Stagnation der Taktfrequenz, aber eine Erweiterung der Prozessorkerne. Aus diesem Grund wird die Parallelität von Anweisungen immer wichtiger, um die Geschwindigkeit moderner Anwendungen zu erhöhen. Da die funktionale Programmierung per Definition keinen Zustand hat und daher keine Nebenwirkungen hat, ist es sicher, Funktionen sicher parallel zu verarbeiten.

GoF-Muster sind nicht veraltet. Sie sind zumindest erforderlich, um die Anforderungen der realen Welt zu modellieren. Wenn Sie jedoch eine funktionale Programmiersprache verwenden, müssen Sie diese in ihre Hybridäquivalente umwandeln. Schließlich haben Sie keine Chance, nur funktionale Programme zu erstellen, wenn Sie Persistenz verwenden. Für die hybriden Elemente Ihres Programms besteht weiterhin die Notwendigkeit, GoF-Muster zu verwenden. Für jedes andere Element, das rein funktional ist, besteht keine Notwendigkeit, GoF-Muster zu verwenden, da es keinen Status gibt.

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 gehen über jedes Sprachparadigma hinaus.

oopexpert
quelle
2
FP kann einen Status haben - nur keinen globalen, gemeinsam genutzten oder veränderlichen Status.
vt5491
2

In der funktionalen Programmierung haben Entwurfsmuster eine andere Bedeutung. Tatsächlich sind die meisten OOP- Entwurfsmuster in der funktionalen Programmierung aufgrund der höheren Abstraktionsebene und der als Bausteine ​​verwendeten HOFs nicht erforderlich .

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

Ali Bayat
quelle
1

Wie in der akzeptierten Antwort angegeben, haben OOP und FP alle ihre spezifischen Muster.

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

  • Adapter. Ich kann mir kaum eine nützliche Programmierplattform vorstellen, die so umfassend (und selbsterfüllt) ist, 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 schöne Oberfläche geben.

  • Dolmetscher. Im Allgemeinen führt jedes Programm nur zwei Dinge aus: Analyseeingabe und Druckausgabe. Mauseingaben müssen analysiert und Fenster-Widgets ausgedruckt werden. Ein eingebetteter Interpreter bietet dem Programm daher zusätzliche Möglichkeiten zum Anpassen von Dingen.

Außerdem ist mir in einer typischen FP-Sprache, Haskell, aufgefallen, dass es etwas Ähnliches wie GoF-Muster gibt, aber mit unterschiedlichen Namen. Meiner Meinung nach deutet dies darauf hin, dass sie dort waren, da einige häufig auftretende Probleme sowohl in FP- als auch in OOP-Sprachen zu lösen sind.

  • Monadentransformator und Dekorateur. Ersteres fügte einer vorhandenen Monade zusätzliche Fähigkeiten hinzu, letzteres fügte einem vorhandenen Objekt zusätzliche Fähigkeiten hinzu.
Erdmotor
quelle
1

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 funktionale Programmierung verwenden, unterscheidet sich der Bereich der Probleme, die Sie lösen, von den OO-Sprachen.

Ich würde keine funktionale Sprache verwenden, um eine Benutzeroberfläche zu schreiben, aber eine der OO-Sprachen wie C # oder Java würde diese Arbeit erleichtern. Wenn ich eine funktionale Sprache schreiben würde, würde ich nicht in Betracht ziehen, OO-Entwurfsmuster zu verwenden.

Vincent Ramdhanie
quelle
1

OOP und FP haben unterschiedliche Ziele. OOP zielt darauf ab, die Komplexität / beweglichen Teile von Softwarekomponenten zu kapseln, und FP zielt darauf ab, die Komplexität und Abhängigkeiten von Softwarekomponenten zu minimieren.

Diese beiden Paradigmen widersprechen sich jedoch nicht unbedingt zu 100% und könnten zusammen angewendet werden, um den Nutzen beider Welten zu erzielen.

Selbst mit einer Sprache, die funktionale Programmierung wie C # nicht nativ unterstützt, können Sie Funktionscode schreiben, wenn Sie die FP-Prinzipien verstehen. Ebenso können Sie OOP-Prinzipien mit F # anwenden, wenn Sie die OOP-Prinzipien, Muster und Best Practices verstehen. Sie würden die richtige Wahl treffen, basierend auf der Situation und dem Problem, das Sie zu lösen versuchen, unabhängig von der verwendeten Programmiersprache.

Dogu Arslan
quelle
1

Einige Muster sind einfacher in einer Sprache zu implementieren, die FP unterstützt. Zum Beispiel kann Strategie mithilfe von Verschlüssen implementiert werden. Je nach Kontext bevorzugen Sie jedoch möglicherweise die Implementierung der Strategie mithilfe eines klassenbasierten Ansatzes, z. B. wenn die Strategien selbst recht kompliziert sind und / oder die Struktur gemeinsam nutzen, die Sie mithilfe der Vorlagenmethode modellieren möchten.

Nach meiner Erfahrung in einer Multi-Paradigmen-Sprache (Ruby) funktioniert die FP-Implementierung in einfachen Fällen gut, aber wenn der Kontext komplizierter ist, passt der GoF OOP-basierte Ansatz besser.

Der FP-Ansatz ersetzt den OOP-Ansatz nicht, sondern ergänzt ihn.

ComDubh
quelle
0

Das wichtigste Merkmal der funktionalen Programmierung, IMHO, ist, dass Sie nur mit Ausdrücken programmieren - Ausdrücken innerhalb von Ausdrücken innerhalb von Ausdrücken, die alle bis zum letzten, endgültigen Ausdruck ausgewertet werden, der "die Maschine bei der Auswertung erwärmt".

Das wichtigste Merkmal der objektorientierten Programmierung, IMHO, ist, dass Sie mit Objekten programmieren, die einen internen Status haben. Sie können keinen internen Zustand in reinen Funktionen haben - objektorientierte Programmiersprachen benötigen Anweisungen , um Dinge geschehen zu lassen. (Es gibt keine Anweisungen in der funktionalen Programmierung.)

Sie vergleichen Äpfel mit Orangen. Die Muster der objektorientierten Programmierung gelten nicht für die Funktionsprogrammierung, da die funktionale Programmierung mit Ausdrücken programmiert und die objektorientierte Programmierung mit internem Zustand programmiert.

Jim Flood
quelle
Hmm, ich hätte bemerken müssen, dass die Frage vor der Beantwortung elf Jahre alt war. :-)
Jim Flood
0

Machen Sie sich bereit.

Es wird viele erschweren, wenn ich behaupte, Designmuster ersetzt und SOLID und DRY entlarvt zu haben. Ich bin niemand. Trotzdem habe ich die kollaborative (Fertigungs-) Architektur korrekt modelliert und die Regeln für Bauprozesse online zusammen mit dem Code und der Wissenschaft dahinter auf meiner Website http://www.powersemantics.com/ veröffentlicht .

Mein Argument ist, dass Entwurfsmuster versuchen, das zu erreichen, was die Fertigung "Massenanpassung" nennt, eine Prozessform, in der jeder Schritt umgestaltet, neu zusammengesetzt und erweitert werden kann. Sie können sich solche Prozesse als nicht kompilierte Skripte vorstellen. Ich werde mein (Online-) Argument hier nicht wiederholen. Kurz gesagt, meine Massenanpassungsarchitektur ersetzt Entwurfsmuster, indem sie diese Flexibilität ohne die chaotische Semantik erreicht. Ich war überrascht, dass mein Modell so gut funktioniert hat, aber die Art und Weise, wie Programmierer Code schreiben, lässt einfach keinen Einfluss darauf, wie die Fertigung die Zusammenarbeit organisiert.

  • Fertigung = Jeder Schritt interagiert mit einem Produkt
  • OOP = Jeder Schritt interagiert mit sich selbst und anderen Modulen und gibt das Produkt wie nutzlose Büroangestellte von Punkt zu Punkt weiter

Diese Architektur muss nie umgestaltet werden. Es gibt auch Regeln für die Zentralisierung und Verteilung, die sich auf die Komplexität auswirken. Um Ihre Frage zu beantworten, ist die funktionale Programmierung ein weiterer Satz von Verarbeitungssemantiken, keine Architektur für benutzerdefinierte Massenprozesse, bei denen 1) das Quellrouting als (Skript-) Dokument vorliegt, das der Benutzer vor dem Auslösen neu schreiben kann, und 2) Module einfach und einfach sein können dynamisch hinzugefügt oder entfernt.

Wir könnten sagen, dass OOP das Paradigma des "hartcodierten Prozesses" ist und dass Entwurfsmuster Wege sind, dieses Paradigma zu vermeiden. Aber genau darum geht es bei der Massenanpassung. Entwurfsmuster verkörpern dynamische Prozesse als chaotischen Hardcode. Es hat einfach keinen Sinn. Die Tatsache, dass F # das Übergeben von Funktionen als Parameter ermöglicht, bedeutet, dass funktionale und OOP- Sprachen gleichermaßen versuchen, eine Massenanpassung selbst durchzuführen.

Wie verwirrend ist das für den Leser, Hardcode, der das Skript darstellt? Überhaupt nicht, wenn Sie glauben, dass die Konsumenten Ihres Compilers für solche Funktionen bezahlen, aber für mich sind solche Funktionen semantische Verschwendung. Sie sind sinnlos, da der Punkt der Massenanpassung darin besteht, Prozesse selbst dynamisch zu gestalten und nicht nur für den Programmierer, der Visual Studio verwendet, dynamisch zu sein.

RBJ
quelle
0

Dies bedeutet, dass ein funktionaler PL auf hoher Ebene (wie OCaml mit Klassen, Modulen usw.) die zwingenden OOP-Sprachen in Bezug auf Typvielfalt und Ausdruckskraft zweifellos ersetzt. Die Abstraktionen lecken nicht, Sie können die meisten Ihrer Ideen direkt im Programm ausdrücken. Daher ersetzt es ja Entwurfsmuster, von denen die meisten im Vergleich zu Funktionsmustern sowieso lächerlich simpel sind.

exa
quelle