Le nouveau battage publicitaire en matière de programmation concerne les paradigmes de programmation fonctionnels. Les langages fonctionnels sont de plus en plus utilisés dans des applications plus grandes et de meilleure qualité. Scala, Haskel, etc. sont en plein essor et d’autres langages plus conservateurs comme Java ont commencé à adopter certains des paradigmes de programmation fonctionnels (voir les clôtures dans Java7 et lazy eval pour les listes en Java8). Cependant, ce que peu de gens savent, c'est que PHP est assez polyvalent pour la programmation fonctionnelle. Tous les principaux concepts de programmation fonctionnels peuvent être exprimés en PHP. Donc, si vous débutez dans la programmation fonctionnelle, préparez-vous à avoir l'esprit vif, et si vous êtes déjà familiarisé avec la programmation fonctionnelle, soyez prêt à vous amuser avec ce tutoriel..
Sans paradigmes de programmation, nous pourrions faire ce que nous voulons de la manière que nous voulons. Bien que cela conduise à une extrême flexibilité, cela conduirait également à des architectures impossibles et à un code très saturé. Ainsi, les paradigmes de programmation ont été inventés pour nous aider, les programmeurs, à réfléchir de manière spécifique à un programme spécifique et à limiter ainsi notre capacité à exprimer notre solution..
Chaque paradigme de programmation nous enlève une liberté:
En programmation fonctionnelle, vous n'avez aucune donnée représentée par des variables.
En programmation fonctionnelle tout est fonction. Et je veux dire tout. Par exemple, un ensemble, comme en mathématiques, peut être représenté par plusieurs fonctions. Un tableau ou une liste est aussi une fonction ou un groupe de fonctions.
Dans la programmation orientée objet, tout est objet. Et un objet est une collection de données et de méthodes qui effectuent des actions sur ces données. Les objets ont un état, un état instable et mutable.
En programmation fonctionnelle, vous n'avez aucune donnée représentée par des variables. Il n'y a pas de conteneur de données. Les données ne sont pas affectées à une variable. Certaines valeurs peuvent être définies et attribuées. Cependant, dans la plupart des cas, ce sont des fonctions assignées à des "variables". J'ai mis des "variables" entre guillemets parce qu'en programmation fonctionnelle elles sont immuable. Même si la plupart des langages de programmation fonctionnels n'imposent pas l'immutabilité, de la même manière que la plupart des langages orientés objet n'appliquent pas d'objet, si vous modifiez la valeur après une affectation, vous ne faites plus de programmation purement fonctionnelle..
Parce que vous n’avez pas de valeurs assignées à des variables, vous avez en programmation fonctionnelle pas d'état.
En l'absence d'état et d'assignations, en programmation fonctionnelle les fonctions n'ont aucun effet secondaire. Et à cause des trois raisons précédentes, les fonctions sont toujours prévisibles. Cela signifie fondamentalement que si vous appelez une fonction avec les mêmes paramètres, encore et encore et encore… vous aurez toujours le même résultat. Ceci est un avantage considérable par rapport à la programmation orientée objet et réduit considérablement la complexité des applications multi-threadées et massivement multi-threadées..
Mais si nous voulons tout exprimer dans des fonctions, nous devons pouvoir les affecter à des paramètres ou les renvoyer à partir d'autres fonctions. Ainsi, la programmation fonctionnelle nécessite le support de fonctions d'ordre supérieur. Cela signifie qu’une fonction peut être affectée à une "variable", envoyée en tant que paramètre à une autre fonction et renvoyée à la suite d’une fonction.
Enfin, comme nous n’avons aucune valeur dans les variables, les boucles while et for sont inhabituelles pour la programmation fonctionnelle et sont remplacées par la récursivité.
Assez parlé et philosophie pour une leçon. Codons!
Configurez un projet PHP dans votre éditeur de code ou IDE préféré. Créer dedans un "Tests"
dossier. Créez deux fichiers: FunSets.php
dans le dossier du projet, et FunSetsTest.php
dans le dossier Tests. Nous allons créer une application, avec des tests, qui représentera le concept des ensembles.
En mathématiques, un ensemble est une collection d'objets distincts, considérés comme un objet à part entière. (Wikipédia)
Cela signifie essentiellement que les ensembles sont un tas de choses dans un seul endroit. Ces ensembles peuvent être et sont caractérisés par des opérations mathématiques: unions, intersections, différences, etc. Et par des propriétés exploitables telles que: contient.
Alors codons! Mais attendez. Comment? Pour respecter les concepts de la programmation fonctionnelle, nous devons appliquer les restrictions suivantes à notre code:
Aucune limite ne s'applique aux tests. En raison de la nature de PHPUnit, nous y utiliserons du code PHP classique orienté objet. De plus, pour mieux adapter nos tests, nous allons regrouper tout notre code de production dans une seule classe..
Si vous êtes un programmeur expérimenté, mais que vous ne connaissez pas la programmation fonctionnelle, le moment est venu d'arrêter de penser comme vous le faites habituellement et soyez prêt à quitter votre zone de confort. Oubliez toutes vos précédentes manières de raisonner sur un problème et imaginez toutes les fonctions intégrées.
La fonction qui définit un ensemble est sa méthode "contient".
function contient ($ set, $ elem) return $ set ($ elem);
OK… Ce n'est pas si évident, voyons comment l'utiliser.
$ set = function ($ element) return true;; contient ($ set, 100);
Eh bien, cela explique un peu mieux. La fonction "contient"
a deux paramètres:
$ set
- représente un ensemble défini comme une fonction.$ elem
- représente un élément défini comme une valeur.Dans ce contexte, tout ce qui "contient"
doit faire est d'appliquer la fonction $ set
avec le paramètre $ elem
. Enveloppons tous dans un test.
La classe FunSetsTest étend PHPUnit_Framework_TestCase private $ funSets; fonction protégée setUp () $ this-> funSets = new FunSets (); function testContainsIsImplemented () // Nous caractérisons un ensemble par sa fonction contient. C'est la fonction de base d'un ensemble. $ set = function ($ element) return true;; $ this-> assertTrue ($ this-> funSets-> contient ($ set, 100));
Et envelopper notre code de production à l'intérieur FunSets.php
dans une classe:
classe FunSets fonction publique contient ($ set, $ elem) return $ set ($ elem);
Vous pouvez réellement exécuter ce test et il passera. L'ensemble que nous avons défini pour ce test est simplement une fonction qui renvoie toujours la valeur true. C'est un "vrai jeu".
Si le chapitre précédent était un peu déroutant ou paraissait inutile en logique, celui-ci le clarifiera un peu. Nous voulons définir un ensemble avec un seul élément, un ensemble singleton. Rappelez-vous que cela doit être une fonction, et nous voudrons l'utiliser comme dans le test ci-dessous.
function testSingletonSetContainsSingleElement () // Un ensemble de singleton est caractérisé par une fonction qui passe à contient retournera la valeur true pour l'élément unique // passé en tant que paramètre. En d'autres termes, un singleton est un ensemble avec un seul élément. $ singleton = $ this-> funSets-> singletonSet (1); $ this-> assertTrue ($ this-> funSets-> contient ($ singleton, 1));
Nous devons définir une fonction appelée "singeltonSet"
avec un paramètre représentant un élément de l'ensemble. Dans le test, c'est le numéro un (1). Ensuite, nous attendons notre contient
méthode, lorsqu'elle est appelée avec une fonction singleton, pour retourner vrai
si le paramètre envoyé est égal à un. Le code qui fait passer le test est le suivant:
fonction publique singletonSet ($ elem) fonction de retour ($ otherElem) use ($ elem) retour $ elem == $ otherElem; ;
Hou la la! C'est fou. Donc, la fonction "singletonSet"
obtient en paramètre un élément comme $ elem
. Ensuite, il retourne une autre fonction qui a un paramètre $ otherElem
et cette seconde fonction va comparer $ elem
à $ otherElem
.
Donc comment ça fonctionne? Tout d'abord, cette ligne:
$ singleton = $ this-> funSets-> singletonSet (1);
est transformé en quoi "singletonSet (1)"
résultats:
$ singleton = function ($ otherElem) return 1 == $ otherElem; ;
ensuite "contient ($ singleton, 1)"
est appelé. Qui, à son tour, appelle tout ce qui est en $ singleton
. Alors le code devient:
$ singleton (1)
Qui exécute en réalité le code qu'il contient avec $ otherElem
ayant la valeur un.
retourne 1 == 1
Ce qui est bien sûr vrai et notre test réussit.
Es-tu déjà souriant? Vous sentez-vous votre cerveau commencer à bouillir? Je l'ai certainement fait lorsque j'ai écrit cet exemple pour la première fois à Scala et je l'ai fait de nouveau lorsque j'ai écrit cet exemple pour la première fois en PHP. Je pense que c'est extraordinaire. Nous avons réussi à définir un ensemble, avec un élément, avec la possibilité de vérifier qu'il contient la valeur que nous lui avons transmise. Nous avons fait tout cela sans cession de valeur. Nous n'avons pas de variable contenant la valeur un ou ayant un état égal à un. Pas d'état, pas de mission, pas de mutabilité, pas de boucles. Nous sommes sur la bonne voie ici.
Maintenant que nous pouvons créer un ensemble avec une seule valeur, nous devons pouvoir créer un ensemble avec plusieurs valeurs. La manière évidente de le faire est de définir le fonctionnement de l’union sur nos postes. L'union de deux ensembles de singleton représentera une autre union avec les deux valeurs. Je veux que vous preniez une minute et que vous réfléchissiez à la solution avant de faire défiler le code, prenez peut-être un aperçu des tests ci-dessous..
function testUnionContainsAllElements () // Une union est caractérisée par une fonction qui obtient 2 ensembles en tant que paramètres et contient tous les ensembles fournis // Nous ne pouvons créer que des singletons à ce stade; nous créons donc 2 singletons et les unissons $ s1 = $ this -> funSets-> singletonSet (1); $ s2 = $ this-> funSets-> singletonSet (2); $ union = $ this-> funSets-> union ($ s1, $ s2); // Maintenant, vérifiez que 1 et 2 font tous les deux partie de l'union $ this-> assertTrue ($ this-> funSets-> includes ($ union, 1)); $ this-> assertTrue ($ this-> funSets-> contient ($ union, 2)); //… et qu'il ne contient pas 3 $ this-> assertFalse ($ this-> funSets-> includes ($ union, 3));
Nous voulons une fonction appelée "syndicat"
qui obtient deux paramètres, les deux ensembles. Rappelez-vous, les ensembles ne sont que des fonctions pour nous, alors notre "syndicat"
fonction aura deux fonctions en tant que paramètres. Ensuite, nous voulons pouvoir vérifier avec "contient"
si l'union contient un élément ou non. Donc notre "syndicat"
fonction doit renvoyer une autre fonction "contient"
peut utiliser.
fonction publique union ($ s1, $ s2) fonction de retour ($ otherElem) use ($ s1, $ s2) retour $ this-> contient ($ s1, $ otherElem) || $ this-> contient ($ s2, $ otherElem); ;
Cela fonctionne réellement très bien. Et cela est parfaitement valable même lorsque votre syndicat est appelé avec un autre syndicat plus un singleton. Il appelle contient
à l'intérieur de lui-même pour chaque paramètre. Si c'est un syndicat, ça va récidiver. C'est si simple.
Nous pouvons appliquer la même logique linéaire avec des modifications mineures pour obtenir les deux fonctions les plus importantes qui caractérisent un ensemble: intersection - contient uniquement les éléments communs entre deux ensembles - et différence - ne contient que les éléments du premier ensemble qui ne font pas partie du deuxième set.
fonction publique intersecter ($ s1, $ s2) fonction de retour ($ otherElem) utiliser ($ s1, $ s2) retour $ this-> contient ($ s1, $ otherElem) && $ ceci-> contient ($ s2, $ otherElem); ; fonction publique diff ($ s1, $ s2) fonction de retour ($ otherElem) use ($ s1, $ s2) retourne $ ceci-> contient ($ s1, $ autreElem) &&! $ ceci-> contient ($ s2 , $ otherElem); ;
Je ne vous inonderai pas avec le code de test pour ces deux méthodes. Les tests sont écrits et vous pouvez les vérifier si vous regardez dans le code ci-joint.
Eh bien, c'est un peu plus compliqué, nous ne pourrons pas résoudre ce problème avec une seule ligne de code. Un filtre est une fonction qui utilise deux paramètres: un ensemble et une fonction de filtrage. Il applique la fonction de filtrage à un ensemble et renvoie un autre ensemble contenant uniquement les éléments satisfaisant la fonction de filtrage. Pour mieux le comprendre, en voici le test.
function testFilterContainsOnlyElementsThatMatchConditionFunction () $ u12 = $ this-> createUnionWithElements (1, 2); $ u123 = $ this-> funSets-> union ($ u12, $ this-> funSets-> singletonSet (3)); // Règle de filtrage, recherche des éléments supérieurs à 1 (signifiant 2 et 3) $ condition = function ($ elem) return $ elem> 1;; // Ensemble filtré $ filtréSet = $ ceci-> funSets-> filtre ($ u123, $ condition); // Vérifier que le jeu filtré ne contient pas 1 $ this-> assertFalse ($ this-> funSets-> contient ($ filtréSet, 1), "Ne devrait pas contenir 1"); // Vérifiez qu'il contient 2 et 3 $ this-> assertTrue ($ this-> funSets-> contient ($ filtréSet, 2), "devrait contenir 2"); $ this-> assertTrue ($ this-> funSets-> contient ($ filtréSet, 3), "devrait contenir 3"); fonction privée createUnionWithElements ($ elem1, $ elem2) $ s1 = $ this-> funSets-> singletonSet ($ elem1); $ s2 = $ this-> funSets-> singletonSet ($ elem2); retourne $ this-> funSets-> union ($ s1, $ s2);
Nous créons un ensemble avec trois éléments: 1, 2, 3. Et nous le plaçons dans la variable $ u123
il est donc facilement identifiable dans nos tests. Ensuite, nous définissons une fonction que nous voulons appliquer au test et la plaçons dans $ condition
. Enfin, nous appelons filtre sur notre $ u123
Fixé avec $ condition
et placez l'ensemble résultant dans $ filtré
. Puis on lance des assertions avec "contient"
pour déterminer si l'ensemble ressemble à ce que nous voulons. Notre fonction de condition est simple, elle retournera true si l'élément est supérieur à un. Donc, notre ensemble final ne devrait contenir que les valeurs deux et trois, et c’est ce que nous vérifions dans nos affirmations..
filtre de fonction publique ($ set, $ condition) fonction de retour ($ otherElem) use ($ set, $ condition) if ($ condition ($ otherElem)) return $ this-> contient ($ set, $ otherElem); retourne faux; ;
Et voilà. Nous avons implémenté le filtrage avec seulement trois lignes de code. Plus précisément, si la condition s'applique à l'élément fourni, nous exécutons un contient sur l'ensemble pour cet élément. Si non, nous revenons juste faux
. C'est tout.
L'étape suivante consiste à créer différentes fonctions de bouclage. Le premier, "pour tous()", va prendre un $ set
et un $ condition
et retour vrai
si $ condition
s'applique à tous les éléments du $ set
. Cela conduit au test suivant:
fonction testForAllCorrectlyTellsIfAllElementsSatisfyCondition () $ u123 = $ this-> createUnionWith123 (); $ higherThanZero = function ($ elem) return $ elem> 0; ; $ higherThanOne = function ($ elem) return $ elem> 1; ; $ higherThanTwo = function ($ elem) return $ elem> 2; ; $ this-> assertTrue ($ this-> funSets-> forall ($ u123, $ higherThanZero)); $ this-> assertFalse ($ this-> funSets-> forall ($ u123, $ higherThanOne)); $ this-> assertFalse ($ this-> funSets-> forall ($ u123, $ higherThanTwo));
Nous avons extrait le $ u123
création du test précédent dans une méthode privée. Ensuite, nous définissons trois conditions différentes: supérieure à zéro, supérieure à un et supérieure à deux. Comme notre ensemble contient les nombres un, deux et trois, seule la condition supérieure à zéro doit retourner la valeur vraie, le reste doit être faux. En effet, nous pouvons faire passer le test à l’aide d’une autre méthode récursive permettant de parcourir tous les éléments.
private $ lié = 1000; fonction privée pour allIterator ($ currentValue, $ set, $ condition) if ($ currentValue> $ this-> lié) return true; elseif ($ this-> contient ($ set, $ currentValue)) return $ condition ($ currentValue) && $ this-> forallIterator ($ currentValue + 1, $ set, $ condition); else return $ this-> forallIterator ($ currentValue + 1, $ set, $ condition); fonction publique forall ($ set, $ condition) return $ this-> forallIterator (- $ this-> lié, $ set, $ condition);
Nous commençons par définir certaines limites pour notre ensemble. Les valeurs doivent être comprises entre -1000 et +1000. C'est une limite raisonnable que nous imposons afin de garder cet exemple assez simple. La fonction "pour tous"
appellera la méthode privée "forallIterator"
avec les paramètres nécessaires pour décider récursivement si tous les éléments respectent la condition. Dans cette fonction, nous testons d'abord si nous sommes hors limites. Si oui, retourne vrai. Ensuite, vérifiez si notre ensemble contient la valeur actuelle et renvoie la valeur actuelle appliquée à la condition avec un "ET" logique avec un appel récursif pour nous-mêmes avec la valeur suivante. Sinon, il suffit de nous appeler avec la valeur suivante et de renvoyer le résultat.
Cela fonctionne très bien, nous pouvons le mettre en œuvre de la même manière que "existe ()"
. Cela retourne vrai
si l'un des éléments remplit la condition.
fonction privée existIterator ($ currentValue, $ set, $ condition) if ($ currentValue> $ this-> lié) return false; elseif ($ this-> contient ($ set, $ currentValue)) return $ condition ($ currentValue) || $ this-> existIterator ($ currentValue + 1, $ set, $ condition); else return $ this-> existIterator ($ currentValue + 1, $ set, $ condition); fonction publique existe ($ set, $ condition) return $ this-> existIterator (- $ this-> lié, $ set, $ condition);
La seule différence est que nous revenons faux
quand hors des limites et nous utilisons "OU" au lieu de "ET" dans le second si.
À présent, "carte()"
sera différent, plus simple et plus court.
mappe de fonction publique ($ set, $ action) fonction de retour ($ currentElem) use ($ set, $ action) return $ this-> existe ($ set, fonction ($ elem) use ($ currentElem, $ action) return $ currentElem == $ action ($ elem);); ;
La cartographie signifie que nous appliquons une action à tous les éléments d'un ensemble. Pour la carte, nous n'avons pas besoin d'itérateur d'assistance, nous pouvons les réutiliser "existe ()"
et renvoyer les éléments de "existe" qui satisfont le résultat de $ action
appliqué à élément $
. Cela peut ne pas être évident au premier site, voyons ce qui se passe.
1, 2
et l'action $ element * 2 (double)
cartographier.existe
avec l'ensemble 1, 2
et la fonction de condition $ currentElement
équivaut à $ elem * 2
.existe ()
itérera sur tous les éléments entre -1000 et +1000, nos limites. Quand il trouve un élément, le double de ce qui vient de "contient"
(la valeur de $ currentElement
) il reviendra vrai
.vrai
pour l'appel à contient avec la valeur deux, lorsque la valeur du courant multipliée par deux, aboutit à deux. Donc, pour le premier élément de l'ensemble, un, il retournera vrai sur deux. Pour le deuxième élément, deux, sur la valeur quatre. Bien que la programmation fonctionnelle soit amusante, elle est loin d’être idéale en PHP. Donc, je ne vous recommande pas d'écrire des applications entières de cette façon. Cependant, maintenant que vous avez appris ce que PHP peut faire de manière fonctionnelle, vous pouvez appliquer une partie de ces connaissances à vos projets quotidiens. Voici un exemple de module d'authentification. le AuthPlugin
La classe fournit une méthode qui reçoit un utilisateur et un mot de passe et fait sa magie pour authentifier l'utilisateur et définir ses autorisations..
class AuthPlugin private $ permissions = array (); fonction authenticate ($ nom d'utilisateur, $ mot de passe) $ this-> verifyUser ($ nom d'utilisateur, $ mot de passe); $ adminModules = new AdminModules (); $ this-> permissions [] = $ adminModules-> allowRead ($ nom d'utilisateur); $ this-> permissions [] = $ adminModules-> allowWrite ($ nom d'utilisateur); $ this-> permissions [] = $ adminModules-> allowExecute ($ nom d'utilisateur); fonction privée verifyUser ($ username, $ password) //… DO USER / PASS CHECKING //… LOAD USER USER, DÉTAILS, ETC.
Cela peut sembler correct, mais le problème est énorme. 80% des "authentifier()"
méthode utilise les informations de la "AdminModules"
. Cela crée une très forte dépendance.
Il serait beaucoup plus raisonnable de prendre les trois appels et de créer une seule méthode sur AdminModules
.
Donc, en déplaçant la génération dans AdminModules
nous avons réussi à réduire trois dépendances à une seule. L'interface publique de AdminModules
a également été réduit de trois à une seule méthode. Cependant, nous n'y sommes pas encore. AuthPlugin
dépend toujours directement de AdminModules
.
Si vous voulez que notre plug-in d'authentification soit utilisable par n'importe quel module, nous devons définir une interface commune pour ces modules. Injectons la dépendance et introduisons une interface.
class AuthPlugin private $ permissions = array (); private $ appModule; function __construct (ApplicationModule $ appModule) $ this-> appModule = $ appModule; fonction authenticate ($ nom d'utilisateur, $ mot de passe) $ this-> verifyUser ($ nom d'utilisateur, $ mot de passe); $ this-> permissions = array_merge ($ this-> permissions, $ this-> appModule-> getPermissions ($ nomutilisateur)); fonction privée verifyUser ($ username, $ password) //… DO USER / PASS CHECKING //… LOAD USER USER, DÉTAILS, ETC.
AuthPlugin
j'ai un constructeur. Il obtient un paramètre de type ApplicationModule
, une interface et des appels "getPermissions ()"
sur cet objet injecté.
interface ApplicationModule fonction publique getPermissions ($ nomutilisateur);
ApplicationModule
définit une seule méthode publique, "getPermissions ()"
, avec un nom d'utilisateur comme paramètre.
La classe AdminModules implémente ApplicationModule // […]
finalement, AdminModules
doit mettre en œuvre le ApplicationModule
interface.
Maintenant, c'est beaucoup mieux. Notre AuthPlugin
ne dépend que d'une interface. AdminModules
dépend de la même interface, donc le AuthPlugin
est devenu agnostique de module. Nous pouvons créer un nombre illimité de modules, tous implémentant ApplicationModule
, et AuthPlugin
sera en mesure de travailler avec chacun d'eux.
Une autre façon d’inverser la dépendance et de créer AdminModule
, ou tout autre module, utiliser le AuthPlugin
est d'injecter dans ces modules une dépendance à AuthPlugin
. AuthPlugin
fournira un moyen de définir la fonction d’authentification et chaque application enverra sa propre "obtenir la permission()"
une fonction.
class AdminModules private $ authPlugin; function __construct (Authentitcation $ authPlugin) $ this-> authPlugin = $ authPlugin; fonction privée allowRead ($ username) return "yes"; fonction privée allowWrite ($ username) return "no"; fonction privée allowExecute ($ username) return $ username == "joe"? "Oui Non"; fonction privée authenticate () $ this-> authPlugin-> setPermissions (function ($ username) $ permissions = array (); $ permissions [] = $ this-> allowRead ($ username); $ permissions [] = $ this-> allowWrite ($ username); $ permissions [] = $ this-> allowExecute ($ username); return $ permissions;); $ this-> authPlugin-> authenticate ();
On commence avec AdminModule
. Il n'implémente plus rien. Cependant, il utilise un objet injecté qui doit implémenter l'authentification. Dans AdminModule
il y aura un "authentifier()"
méthode qui appellera "setPermissions ()"
sur AuthPlugin
et passez dans la fonction qui doit être utilisée.
interface Authentication function setPermissions ($ permissionGrantingFunction); fonction authenticate ();
L'interface d'authentification définit simplement les deux méthodes.
La classe AuthPlugin implémente l'authentification private $ permissions = array (); private $ appModule; private $ permissionsFunction; function __construct (ApplicationModule $ appModule) $ this-> appModule = $ appModule; fonction authenticate ($ nom d'utilisateur, $ mot de passe) $ this-> verifyUser ($ nom d'utilisateur, $ mot de passe); $ this-> permissions = $ this-> permissionsFunction ($ nom d'utilisateur); fonction privée verifyUser ($ username, $ password) //… DO USER / PASS CHECKING //… LOAD USER USER, DÉTAILS, ETC. fonction publique setPermissions ($ permissionGrantingFunction) $ this-> permissionsFunction = $ permissionGrantingFunction;
finalement, AuthPlugin
implémente l'authentification et définit la fonction entrante dans un attribut de classe privée. ensuite, "authentification()"
devient une méthode stupide. Il appelle simplement la fonction et définit ensuite la valeur de retour. Il est complètement découplé de tout ce qui entre.
Si nous examinons le schéma, il y a deux changements importants:
AdminModule
, AuthPlugin
est celui qui implémente l'interface.AuthPlugin
sera "Call Back" AdminModule
, ou quel que soit le module envoyé dans la fonction des autorisations.Il n'y a pas de réponse correcte à cette question. Je dirais que si le processus de détermination des autorisations dépend fortement du module d'application, l'approche orientée objet est plus appropriée. Cependant, si vous pensez que chaque module d’application devrait pouvoir fournir une fonction d’authentification, votre AuthPlugin
n'est qu'un squelette fournissant la fonctionnalité d'authentification mais sans rien connaître des utilisateurs ni des procédures, vous pouvez alors choisir l'approche fonctionnelle.
L’approche fonctionnelle rend votre AuthPlugin
très abstrait et vous pouvez en dépendre. Cependant, si vous prévoyez de permettre à votre AuthPlugin
pour faire plus et en savoir plus sur les utilisateurs et votre système, cela deviendra trop concret et vous ne voudrez plus en dépendre. Dans ce cas, choisissez la manière orientée objet et laissez le béton AuthPlugin
dépend des modules d'application plus abstraits.