Wie Patryk Ćwiek in the comment above hervorhebt, treffen Sie auf die Expression Problem, also müssen Sie das eine oder andere wählen.
Wenn die Fähigkeit, weitere Datentypen hinzuzufügen, für Sie wichtiger ist als die Möglichkeit, einfach mehr Verhalten hinzuzufügen, ist ein interface-basierter Ansatz möglicherweise besser geeignet.
In F # können Sie noch objektorientierte Schnittstellen definieren:
type IPaymentInstrument =
abstract member PrintInstrumentName : unit -> unit
abstract member PrintRequisites : unit -> unit
Sie auch Klassen, die diese Schnittstelle implementieren erstellen können. Hier ist Check
, und ich werde CreditCard
als Übung dem Leser überlassen:
type Check(number : string) =
interface IPaymentInstrument with
member this.PrintInstrumentName() = printfn "check"
member this.PrintRequisites() = printfn "check %s" number
Doch wenn Sie die objektorientierte Art und Weise gehen wollen, sollten Sie die SOLID principles zu betrachten beginnen, eine davon ist die Interface Segregation Principle (ISP). Sobald Sie den ISP aggressiv, you'll ultimately end up with interfaces with a single member, like this starten Anwendung:
type IPaymentInstrumentNamePrinter =
abstract member PrintInstrumentName : unit -> unit
type IPaymentInstrumentRequisitePrinter =
abstract member PrintRequisites : unit -> unit
können Sie immer noch diese in Klassen implementieren:
type Check2(number : string) =
interface IPaymentInstrumentNamePrinter with
member this.PrintInstrumentName() = printfn "check"
interface IPaymentInstrumentRequisitePrinter with
member this.PrintRequisites() = printfn "check %s" number
Dies beginnt sich jetzt etwas lächerlich zu sein scheinen. Wenn Sie F # verwenden, dann gehen Sie zu , um alle Probleme zu lösen, eine Schnittstelle mit einem einzelnen Mitglied zu definieren?
Warum nicht stattdessen Funktionen?
Beide gewünschten Schnittstellenelemente haben den Typ unit -> unit
(nicht besonders "funktionell" aussehende Art), also warum nicht solche Funktionen herumreichen, und auf den Schnittstellenoverhead verzichten?
Mit den Funktionen printInstrumentName
und printRequisites
aus dem OP haben Sie bereits das gewünschte Verhalten. Wenn Sie sie in polymorphen ‚Objekte‘ machen wollen, dass ‚implementieren‘ die gewünschte Schnittstelle können Sie über sie schließen:
let myCheck = Check "1234"
let myNamePrinter() = printInstrumentName myCheck
In Functional Programming, wir diese Dinge nicht nennen Objekte, sondern Verschlüsse. Anstatt Daten mit Verhalten zu sein, sind sie Verhalten mit Daten.
Sie könnten diese Member-Funktionen machen, die etwas sauberer wären, aber immer noch die übereinstimmenden –
Es ist eine Seite von [Ausdruck Problem] (http://c2.com/cgi/wiki?ExpressionProblem), während OOP-Ansatz ist das andere. Ergo, Sie können die Musterübereinstimmung wirklich nicht beseitigen. –
Ich stimme dem Kommentar von @ PatrykĆwiek zu. Die Stärke der Musterübereinstimmung besteht darin, dass Sie das "Rauschen" der OOP-Mechanismen eliminieren, was in diesem Fall kaum nützlich ist. In realen Projekten sitzen die inneren Körper jeder Niederlassung in separaten Funktionen, was die Entwicklung und das Testen vereinfacht. OTOH, wenn an einem Tag "PaymentInstrument" groß wird und von verschiedenen Leuten entwickelt wird, dann können Sie schnell zum OOP-Ansatz wechseln, während Sie bestehende separate Verarbeitungsfunktionen beibehalten. – bytebuster