Wiederholbarer Mustervergleich

8

Betrachten Sie das folgende einfache Beispiel.

%Vor%

Wie Sie sehen können, wird dieselbe Mustervergleichslogik in zwei Funktionen wiederholt. Wenn ich OOP verwenden würde, würde ich die Schnittstelle IPaymentInstrument erstellen und zwei Operationen definieren:

PrintInstrumentName und PrintRequisites

und dann Klassen implementieren - eine pro Zahlungsinstrument. Um das Instrument in Abhängigkeit von einigen externen Bedingungen zu instanziieren, würde ich (zum Beispiel) das Fabrikmuster ( PaymentInstrumentFactory ) verwenden.

Wenn ich ein neues Zahlungsinstrument hinzufügen müsste, muss ich nur eine neue Klasse hinzufügen, die IPaymentInstrument interface implementiert und die Factory Instanziierungslogik aktualisiert. Anderer Code, der diese Klassen verwendet, bleibt unverändert.

Aber wenn ich den funktionalen Ansatz verwende, sollte ich jede -Funktion aktualisieren, bei der Mustererkennung für diesen Typ existiert.

Wenn es viele Funktionen gibt, die PaymentInstrument type verwenden, ist das ein Problem.

Wie kann dieses Problem mit einem funktionalen Ansatz behoben werden?

    
eternity 23.10.2015, 08:57
quelle

2 Antworten

1

Mit Mark Seemanns Antwort kam ich zu einer solchen Designentscheidung.

%Vor%

Und Verwendung

%Vor%

Wie Sie sehen können, führt die Funktion getTypeOperations die Rolle des Fabrikmusters aus. Um Funktionen in einem Bündel zu aggregieren, benutze ich einen einfachen Datensatztyp (jedoch sind gemäß den F # Designrichtlinien Ссылка Schnittstellen vorhanden Vorgezogen zu einer solchen Entscheidung, aber ich bin daran interessiert, es in funktionalen Ansatz zu tun, um es jetzt besser zu verstehen).

Ich habe bekommen, was ich wollte - Pattern Matching gibt es nur an einer Stelle.

    
eternity 24.10.2015, 14:59
quelle
17
___ tag123f ___ F # ist eine prägnante, ausdrucksstarke und effiziente funktionale und objektorientierte Sprache für .NET, mit der Sie einfachen Code zur Lösung komplexer Probleme schreiben können. ___ tag123funktionale Programmierung ___ Funktionale Programmierung ist ein Programmierparadigma, das auf der Erzeugung von Abstraktionen unter Verwendung von Funktionen basiert, die Nebeneffekte und Zustandsänderungen vermeidet. Reine funktionale Programmierung ist threadsicher. ___ qstntxt ___

Betrachten Sie das folgende einfache Beispiel.

%Vor%

Wie Sie sehen können, wird dieselbe Mustervergleichslogik in zwei Funktionen wiederholt. Wenn ich OOP verwenden würde, würde ich die Schnittstelle Check erstellen und zwei Operationen definieren:

CreditCard und unit -> unit

und dann Klassen implementieren - eine pro Zahlungsinstrument. Um das Instrument in Abhängigkeit von einigen externen Bedingungen zu instanziieren, würde ich (zum Beispiel) das Fabrikmuster ( printInstrumentName ) verwenden.

Wenn ich ein neues Zahlungsinstrument hinzufügen müsste, muss ich nur eine neue Klasse hinzufügen, die printRequisites interface implementiert und die Factory Instanziierungslogik aktualisiert. Anderer Code, der diese Klassen verwendet, bleibt unverändert.

Aber wenn ich den funktionalen Ansatz verwende, sollte ich jede -Funktion aktualisieren, bei der Mustererkennung für diesen Typ existiert.

Wenn es viele Funktionen gibt, die %code% type verwenden, ist das ein Problem.

Wie kann dieses Problem mit einem funktionalen Ansatz behoben werden?

    
___ qstnhdr ___ Wiederholbarer Mustervergleich ___ answer3300782 ___

Wie Patryk Ćwiek in dem obigen Kommentar darauf hinweist, begegnen Sie dem Ausdruck Problem , so dass Sie die eine oder andere wählen müssen.

Wenn die Möglichkeit, weitere Datentypen hinzuzufügen, für Sie wichtiger ist als die Möglichkeit, einfach mehr Verhalten hinzuzufügen, ist ein schnittstellenbasierter Ansatz möglicherweise geeigneter.

In F # können Sie noch objektorientierte Schnittstellen definieren:

%Vor%

Sie können auch Klassen erstellen, die diese Schnittstelle implementieren. Hier ist %code% , und ich werde %code% als Übung für den Leser hinterlassen:

%Vor%

Wenn Sie jedoch den objektorientierten Weg gehen wollen, sollten Sie die SOLID-Prinzipien , eine davon ist das Interface Separation Principle (ISP). Sobald Sie beginnen, den ISP aggressiv zu bewerben, werden Sie schließlich mit Schnittstellen enden mit einem einzigen Mitglied, so :

%Vor%

Sie können dies immer noch in Klassen implementieren:

%Vor%

Das fängt jetzt an, etwas lächerlich zu wirken. Wenn Sie F # verwenden, dann warum sollten Sie alle Probleme bei der Definition einer Schnittstelle mit einem einzelnen Member aufgreifen?

Verwenden Sie stattdessen Funktionen ?

Beide gewünschten Interface-Member haben den Typ %code% (obwohl kein besonders "funktional" aussehender Typ), also warum nicht solche Funktionen herumreichen und auf den Interface-Overhead verzichten?

Mit den Funktionen %code% und %code% aus dem OP haben Sie bereits das gewünschte Verhalten. Wenn Sie sie in polymorphe 'Objekte' verwandeln wollen, die die gewünschte Schnittstelle 'implementieren', können Sie über sie schließen:

%Vor%

In der funktionalen Programmierung nennen wir diese Dinge nicht Objekte , sondern closures . Statt Daten mit Verhalten zu sein, sind sie Verhalten mit Daten .

    
___ answer33319572 ___

Mit Mark Seemanns Antwort kam ich zu einer solchen Designentscheidung.

%Vor%

Und Verwendung

%Vor%

Wie Sie sehen können, führt die Funktion %code% die Rolle des Fabrikmusters aus. Um Funktionen in einem Bündel zu aggregieren, benutze ich einen einfachen Datensatztyp (jedoch sind gemäß den F # Designrichtlinien Ссылка Schnittstellen vorhanden Vorgezogen zu einer solchen Entscheidung, aber ich bin daran interessiert, es in funktionalen Ansatz zu tun, um es jetzt besser zu verstehen).

Ich habe bekommen, was ich wollte - Pattern Matching gibt es nur an einer Stelle.

    
___
Mark Seemann 23.10.2015 11:02
quelle

Tags und Links