Le modèle de conception de stratégie est souvent considéré comme un substitut des fonctions de première classe dans des langues qui ne les manquent pas.
Donc, par exemple, disons que vous vouliez passer la fonctionnalité dans un objet. In Java Vous devez transmettre l'objet un autre objet qui encapsule le comportement souhaité. Dans une langue telle que Ruby, vous venez de transmettre la fonctionnalité elle-même sous la forme d'une fonction anonyme .
Cependant, je pensais à cela et j'ai décidé que la stratégie peut-être que la stratégie offre plus qu'une simple fonction anonyme.
En effet, un objet peut contenir l'état qui existe indépendamment de la période où sa méthode fonctionne. Toutefois, une fonction anonyme ne peut en elle-même que l'état qui cesse d'exister au moment où la fonction termine l'exécution.
Dans une langue orientée objet prenant en charge les fonctions de première classe, le modèle de stratégie a-t-il un avantage sur l'utilisation de fonctions?
Lorsque la langue prend en charge les références à la fonction ( Java fait depuis la version 8 ), il s'agit souvent d'une bonne alternative pour les stratégies, car elles expriment généralement la même chose avec moins de syntaxe. Cependant, il y a des cas où un véritable objet peut être utile.
Une interface de stratégie peut avoir plusieurs méthodes. Prenons une interface RouteFindingStragegy
comme exemple, qui encapsule des algorithmes de recherche de route différents. Il pourrait déclarer des méthodes comme
Route findShortestRoute(Node start, Node destination)
boolean doesRouteExist(Node start, Node destination)
Route[] findAllPossibleRoutes(Node start, Node destination)
Route findShortestRouteToClosestDestination(Node start, Node[] destinations)
Route findTravelingSalesmanRoute(Node[] stations)
qui serait alors tous mis en œuvre par la stratégie. Certains algorithmes de recherche d'itinéraire peuvent permettre des optimisations internes pour certains de ces cas d'utilisation et certains pourraient non, la mise en œuvre peut donc décider de la manière de mettre en œuvre chacune de ces méthodes.
Un autre cas est lorsque la stratégie a un état intérieur. Bien sûr, dans certaines langues, la fermeture peut avoir un état intérieur, mais lorsque cet état intérieur devient très complexe, il devient souvent plus élégant de promouvoir la fermeture à une classe à part entière.
Il n'est pas vrai qu'une fonction anonyme ne peut contenir que l'état qui cesse d'exister lorsque la fonction termine l'exécution.
Prenez l'exemple suivant en commun LISP:
(defun number-strings (ss)
(let ((counter 0))
(mapcar #'(lambda (s) (format nil "~a: ~a" (incf counter) s)) ss)))
Cette fonction prend une liste de chaînes et répeint un compteur à chaque élément de la liste. Donc, par exemple, invoquant
(number-strings '("a" "b" "c"))
donne
("1: a" "2: b" "3: c")
La fonction number-strings
Utilise en interne une fonction anonyme avec une variable counter
qui contient l'état (la valeur actuelle du compteur) qui est réutilisée chaque fois que la fonction est invoquée.
En général, vous pouvez penser à une fermeture comme objet avec une seule méthode. Alternativement, un objet est une collection de fermetures qui partagent les mêmes variables fermées. Je ne suis donc pas sûr de savoir s'il y a des cas dans lesquels vous devez utiliser un objet au lieu d'une fermeture: je dirais que les deux sont des moyens de regarder le même modèle de perspectives différentes.
En particulier, le modèle de stratégie nécessite un objet avec une seule méthode, une fermeture devrait donc faire le travail. Mais, comme l'a observé Philipp dans sa réponse, en fonction des circonstances (État complexe) et de langages de programmation, vous pouvez obtenir une solution plus élégante en utilisant des objets.
Ce n'est pas parce que deux designs peuvent résoudre le même problème que cela ne signifie pas qu'ils sont des substitutions directes l'une pour l'autre.
Si vous devez suivre l'état dans un programme fonctionnel, vous ne mutez pas une variable fermée sur la variable, même si la langue le permet. Vous arrangez d'appeler une fonction qui prend dans un état sous forme d'argument et renvoie le nouvel état comme valeur de retour.
Votre architecture sera très différente, mais vous accomplirez le même objectif. N'essayez pas de forcer les modèles de paradigme directement sur l'autre.
La stratégie est un concept, une recette utile pour résoudre un problème particulier et récurrent. Ce n'est pas une construction de langue, ni une forme de mise en œuvre. Une fermeture peut être utilisée pour mettre en œuvre une stratégie un jour et un observateur le lendemain.
La stratégie terme est principalement utile dans les conversations avec d'autres programmeurs pour exprimer votre intention de manière concise. Il n'y a rien de magique à ce sujet.