L'inversion de dépendance dans la POO signifie que vous codez contre une interface qui est ensuite fournie par une implémentation dans un objet.
Les langages prenant en charge des fonctions de langage supérieures peuvent souvent résoudre des problèmes simples d'inversion de dépendance en transmettant le comportement comme une fonction au lieu d'un objet qui implémente une interface dans le sens OO.
Dans de tels langages, la signature de la fonction peut devenir l'interface et une fonction est transmise à la place d'un objet traditionnel pour fournir le comportement souhaité. Le trou au milieu est un bon exemple de cela.
Cela vous permet d'obtenir le même résultat avec moins de code et plus d'expression, car vous n'avez pas besoin d'implémenter une classe entière conforme à une interface (OOP) pour fournir le comportement souhaité à l'appelant. Au lieu de cela, vous pouvez simplement passer une définition de fonction simple. En bref: le code est souvent plus facile à maintenir, plus expressif et plus flexible lorsque l’on utilise des fonctions d’ordre supérieur.
Un exemple en C #
Approche traditionnelle:
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);
Avec des fonctions d'ordre supérieur:
public IEnumerable<Customer> FilterCustomers(Func<Customer, bool> filter, IEnumerable<Customers> customers)
{
foreach(var customer in customers)
{
if(filter(customer))
{
yield return customer;
}
}
}
Maintenant, l'implémentation et l'invocation deviennent moins lourdes. Nous n'avons plus besoin de fournir une implémentation IFilter. Nous n'avons plus besoin d'implémenter des classes pour les filtres.
var filteredDataByName = FilterCustomers(x => x.Name.Equals("CustomerName"), customers);
var filteredDataByBirthday = FilterCustomers(x => x.Birthday == SomeDateTime, customers);
Bien sûr, cela peut déjà être fait par LinQ en C #. Je viens d'utiliser cet exemple pour illustrer le fait qu'il est plus facile et plus flexible d'utiliser des fonctions d'ordre supérieur au lieu d'objets implémentant une interface.
IFilter<Customer>
n'est pas une application du tout. La fonction d'ordre supérieur est beaucoup plus flexible, ce qui représente un avantage considérable, et le fait de pouvoir les écrire en ligne est un autre avantage considérable. Les Lambda sont également beaucoup plus faciles à capturer des variables locales.public delegate bool CustomerFilter(Customer customer)
. dans les langages fonctionnels purs comme haskell, le repliement des types est trivial:type customerFilter = Customer -> Bool
Si vous voulez changer le comportement d'une fonction
vous pourriez passer une autre fonction
qui met en œuvre le comportement que vous voulez être différent.
"doThisWith" est une fonction d'ordre supérieur, car elle prend une autre fonction en tant qu'argument.
Par exemple, vous pourriez avoir
la source
Réponse courte:
L'injection de dépendance classique / Inversion of Control utilise une interface de classe comme espace réservé pour les fonctionnalités dépendantes. Cette interface est implémentée par une classe.
Au lieu de Interface / ClassImplementation, de nombreuses dépendances peuvent être plus facilement implémentées avec une fonction de délégué.
Vous trouvez un exemple à la fois dans c # à ioc-factory-pros-and-contras-for-interface-versus-delegues .
la source
Comparez ceci:
avec:
La deuxième version est un moyen utilisé par Java 8 pour réduire le code passe-partout (boucles, etc.) en fournissant des fonctions d'ordre supérieur telles
filter
que celles qui permettent de passer le minimum strict (c'est-à-dire la dépendance à injecter - l'expression lambda).la source
Piggy-backing exemple de LennyProgrammers ...
Parmi les autres exemples manqués, vous pouvez utiliser des fonctions d'ordre supérieur avec une application de fonction partielle (PFA) pour lier (ou "injecter") des dépendances dans une fonction (via sa liste d'arguments) afin de créer une nouvelle fonction.
Si au lieu de:
nous (pour être conventionnel dans la façon dont la PFA est habituellement faite) avons la fonction de travailleur de bas niveau comme (permutation d'argument):
On peut alors appliquer partiellement doThisWith comme suit:
Ce qui nous permet d'utiliser plus tard la nouvelle fonction comme suit:
Ou même:
Voir aussi: https://ramdajs.com/docs/#partial
... et, oui, les additionneurs / multiplicateurs sont des exemples sans imagination. Un meilleur exemple serait une fonction qui prend des messages et les enregistre ou les envoie par courrier électronique en fonction de la fonction "consommateur" transmise en tant que dépendance.
En élargissant cette idée, des listes d'arguments encore plus longues peuvent être progressivement réduites à des fonctions de plus en plus spécialisées avec des listes d'arguments de plus en plus courtes. Bien entendu, chacune de ces fonctions peut être transférée à d'autres fonctions sous forme de dépendances à appliquer partiellement.
La programmation orientée objet est pratique si vous avez besoin d'un ensemble d'éléments comportant plusieurs opérations étroitement liées, mais il s'avère également indispensable de créer un ensemble de classes comportant chacune une méthode "do it" publique, comme le "Royaume des noms".
la source