Abhängigkeitsinversion in OOP bedeutet, dass Sie gegen eine Schnittstelle codieren, die dann von einer Implementierung in einem Objekt bereitgestellt wird.
Sprachen, die Funktionen für höhere Sprachen unterstützen, können oft einfache Abhängigkeitsinversionsprobleme lösen, indem sie das Verhalten als Funktion anstelle eines Objekts übergeben, das eine Schnittstelle im OO-Sinne implementiert.
In solchen Sprachen kann die Signatur der Funktion zur Schnittstelle werden, und eine Funktion wird anstelle eines herkömmlichen Objekts übergeben, um das gewünschte Verhalten zu erzielen. Das Loch im mittleren Muster ist dafür ein gutes Beispiel.
Auf diese Weise erzielen Sie dasselbe Ergebnis mit weniger Code und mehr Ausdruckskraft, da Sie keine ganze Klasse implementieren müssen, die einer OOP-Schnittstelle entspricht, um das gewünschte Verhalten für den Aufrufer bereitzustellen. Stattdessen können Sie einfach eine einfache Funktionsdefinition übergeben. Kurz gesagt: Code ist oft einfacher zu pflegen, aussagekräftiger und flexibler, wenn Funktionen höherer Ordnung verwendet werden.
Ein Beispiel in C #
Traditioneller Ansatz:
public IEnumerable<Customer> FilterCustomers(IFilter<Customer> filter, IEnumerable<Customers> customers)
{
foreach(var customer in customers)
{
if(filter.Matches(customer))
{
yield return customer;
}
}
}
//now you've got to implement all these filters
class CustomerNameFilter : IFilter<Customer> /*...*/
class CustomerBirthdayFilter : IFilter<Customer> /*...*/
//the invocation looks like this
var filteredDataByName = FilterCustomers(new CustomerNameFilter("SomeName"), customers);
var filteredDataBybirthDay = FilterCustomers(new CustomerBirthdayFilter(SomeDate), customers);
Mit Funktionen höherer Ordnung:
public IEnumerable<Customer> FilterCustomers(Func<Customer, bool> filter, IEnumerable<Customers> customers)
{
foreach(var customer in customers)
{
if(filter(customer))
{
yield return customer;
}
}
}
Jetzt werden die Implementierung und der Aufruf weniger umständlich. Wir müssen keine IFilter-Implementierung mehr bereitstellen. Wir müssen keine Klassen mehr für die Filter implementieren.
var filteredDataByName = FilterCustomers(x => x.Name.Equals("CustomerName"), customers);
var filteredDataByBirthday = FilterCustomers(x => x.Birthday == SomeDateTime, customers);
Dies kann natürlich bereits von LinQ in C # durchgeführt werden. Ich habe dieses Beispiel nur verwendet, um zu veranschaulichen, dass es einfacher und flexibler ist, Funktionen höherer Ordnung anstelle von Objekten zu verwenden, die eine Schnittstelle implementieren.
IFilter<Customer>
ist überhaupt keine Durchsetzung. Die Funktion höherer Ordnung ist wesentlich flexibler, was ein großer Vorteil ist, und die Möglichkeit, sie inline zu schreiben, ist ein weiterer großer Vorteil. Lambdas sind auch viel einfacher in der Lage, lokale Variablen zu erfassen.public delegate bool CustomerFilter(Customer customer)
. in reinen funktionalen sprachen wie haskell ist das aliasing von typen trivial:type customerFilter = Customer -> Bool
Wenn Sie das Verhalten einer Funktion ändern möchten
Sie könnten eine andere Funktion übergeben
welche implementiert das Verhalten, das Sie anders sein möchten.
"doThisWith" ist eine Funktion höherer Ordnung, da eine andere Funktion als Argument verwendet wird.
Zum Beispiel könntest du haben
quelle
Kurze Antwort:
Classical Dependency Injection / Inversion of Control verwendet eine Klassenschnittstelle als Platzhalter für abhängige Funktionen. Diese Schnittstelle wird von einer Klasse implementiert.
Anstelle von Interface / ClassImplementation können viele Abhängigkeiten mit einer Delegate-Funktion einfacher implementiert werden.
Ein Beispiel für beides finden Sie in c # unter ioc-factory-pros-and-contras-for-interface-versus-delegates .
quelle
Vergleichen Sie dies:
mit:
Die zweite Version ist die Methode von Java 8 zur Reduzierung von Boilerplate-Code (Schleifen usw.), indem Funktionen höherer Ordnung bereitgestellt werden, mit
filter
denen Sie das absolute Minimum (dh die zu injizierende Abhängigkeit - der Lambda-Ausdruck) überschreiten können.quelle
Huckepack von LennyProgrammers Beispiel ...
Eines der Dinge, die in den anderen Beispielen übersehen wurden, ist, dass Sie Funktionen höherer Ordnung zusammen mit Partial Function Application (PFA) verwenden können, um Abhängigkeiten in eine Funktion (über ihre Argumentliste) zu binden (oder "einzufügen"), um eine neue Funktion zu erstellen.
Wenn anstelle von:
Wir (um konventionell zu sein, wie PFA normalerweise gemacht wird) haben die Low-Level-Worker-Funktion als (Austausch der Argumentreihenfolge):
Dann können wir doThisWith teilweise so anwenden :
Damit können wir die neue Funktion später wie folgt nutzen:
Oder auch:
Siehe auch: https://ramdajs.com/docs/#partial
... und Addierer / Multiplikatoren sind einfallslose Beispiele. Ein besseres Beispiel wäre eine Funktion, die Nachrichten entgegennimmt und sie protokolliert oder per E-Mail versendet, je nachdem, was die "Consumer" -Funktion als Abhängigkeit übergeben hat.
Um diese Idee zu erweitern, können noch längere Argumentlisten schrittweise auf immer spezialisiertere Funktionen mit immer kürzeren Argumentlisten eingegrenzt werden, und natürlich kann jede dieser Funktionen als teilweise anzuwendende Abhängigkeiten an andere Funktionen übergeben werden.
OOP ist nett, wenn Sie ein Bündel von Dingen mit mehreren eng verwandten Operationen benötigen, aber es wird zu einer Arbeit, um eine Reihe von Klassen mit jeweils einer öffentlichen "do it" -Methode zu erstellen, a la "The Kingdom of Nouns".
quelle