Noul hype în programare se referă la paradigme de programare funcțională. Limbile funcționale sunt utilizate din ce în ce mai mult în aplicații mai mari și mai bune. Scala, Haskel etc. sunt înfloritoare și alte limbi mai conservatoare, cum ar fi Java, au început să adopte unele paradigme de programare funcțională (a se vedea închiderea în Java7 și evalul leneș pentru listele din Java8). Cu toate acestea, ceea ce puțini oameni știu este că PHP este destul de versatil când vine vorba de programarea funcțională. Toate conceptele principale de programare funcțională pot fi exprimate în PHP. Deci, dacă sunteți nou în programarea funcțională, fiți pregătiți să vă răstălmăciți mintea și dacă sunteți deja familiarizați cu programarea funcțională, fiți pregătiți să vă distrați cu acest tutorial.
Fără paradigme de programare am putea să facem tot ce vrem în orice mod dorim. În timp ce acest lucru ar duce la o flexibilitate extremă, ar duce, de asemenea, la arhitecturi imposibile și un cod foarte umflat. Astfel, paradigmele de programare au fost inventate pentru a ne ajuta, programatorii, să gândim într-un mod specific despre un anumit program și, în acest fel, să ne limităm capacitatea de a ne exprima soluția.
Fiecare paradigmă de programare îndepărtează o libertate de la noi:
În programarea funcțională nu aveți date reprezentate de variabile.
În programarea funcțională totul este o funcție. Și vreau să spun totul. De exemplu, un set, ca și în matematică, poate fi reprezentat ca mai multe funcții. Un tabel sau o listă este, de asemenea, o funcție sau un grup de funcții.
În programarea orientată obiect totul este un obiect. Un obiect este o colecție de date și metode care fac acțiuni asupra acelor date. Obiectele au o stare, o stare volatilă, mutabilă.
În programarea funcțională nu aveți date reprezentate de variabile. Nu există containere de date. Datele nu sunt atribuite unei variabile. Unele valori pot fi definite și atribuite. Cu toate acestea, în majoritatea cazurilor acestea sunt funcții atribuite "variabilelor". Am pus "variabile" între citate, deoarece în programarea funcțională sunt imuabil. Chiar dacă cele mai multe limbi de programare funcționale nu impun immutabilitate, în același mod în care majoritatea limbilor orientate spre obiecte nu aplică obiecte, dacă schimbați valoarea după o sarcină pe care nu o mai faceți programarea funcțională pură.
Deoarece nu aveți valori atribuite variabilelor, în programarea funcțională pe care o aveți nici un stat.
Din cauza lipsei de stat și a unor sarcini, în programarea funcțională funcțiile nu au nici un efect secundar. Și din cauza celor trei motive anterioare, funcțiile sunt întotdeauna previzibile. Acest lucru înseamnă că, dacă numiți o funcție cu aceiași parametri din nou și din nou ... veți avea întotdeauna același rezultat. Acesta este un avantaj imens față de programarea orientată pe obiecte și reduce foarte mult complexitatea aplicațiilor multi-filetate și multi-filetate.
Dar, dacă vrem să exprimăm totul în funcții, trebuie să putem să le atribuim parametrilor sau să le reîntoarcem de la alte funcții. Astfel, programarea funcțională necesită suport pentru funcții de ordin superior. Acest lucru înseamnă în principiu că o funcție poate fi atribuită unei "variabile", trimisă ca parametru unei alte funcții și returnată ca rezultat al unei funcții.
În cele din urmă, deoarece nu avem valori în variabile, în timp ce buclele sunt neobișnuite pentru programarea funcțională și sunt înlocuite cu recursivitate.
Destul vorbind și filosofia unei lecții. Să codificăm!
Configurați un proiect PHP în IDE sau într-un editor de cod preferat. Creați în el a „Teste“
pliant. Creați două fișiere: FunSets.php
în dosarul proiectului și FunSetsTest.php
în dosarul Teste. Vom crea o aplicație, cu teste, care va reprezenta conceptul de seturi.
În matematică, un set este o colecție de obiecte distincte, considerată un obiect în sine. (Wikipedia)
Asta inseamna practic ca seturile sunt o gramada de lucruri intr-un singur loc. Aceste seturi pot fi și se caracterizează prin operații matematice: uniuni, intersecții, diferențe etc. Și prin proprietăți acționabile precum: conține.
Deci, să codificăm! Dar asteapta. Cum? Ei bine, pentru a respecta conceptele programării funcționale, va trebui să aplicăm următoarele restricții codului nostru:
Nicio limitare nu se aplică testelor. Din cauza naturii PHPUnit, vom folosi codul PHP orientat obiect clasic acolo. De asemenea, pentru a satisface mai bine testele noastre, vom împacheta întregul cod de producție într-o singură clasă.
Dacă sunteți un programator condimentat, dar nu este familiarizat cu programarea funcțională, acum este momentul să nu mai gândiți așa cum faceți de obicei și să fiți gata să vă părăsiți zona de confort. Uitați de toate modurile anterioare de raționament despre o problemă și imaginați-vă toate funcțiile.
Funcția de definire a unui set este metoda "conține".
funcția conține ($ set, $ elem) return $ set ($ elem);
OK ... Nu este așa de evident, așa că să vedem cum i-am folosi.
$ set = funcție ($ element) return true;; conține ($ set, 100);
Ei bine, asta explică ceva mai bine. Functia „Conține“
are doi parametri:
$ set
- reprezintă un set definit ca o funcție.$ elem
- reprezintă un element definit ca o valoare.În acest context, toate astea „Conține“
trebuie să faceți este să aplicați funcția în $ set
cu parametrul $ elem
. Să o înfășurăm pe toate într-un test.
clasa FunSetsTest extinde PHPUnit_Framework_TestCase private $ funSets; funcția protejată setUp () $ this-> funSets = FunSets noi (); test functionContainsIsImplemented () // Noi caracterizam un set prin care contine functia. Este funcția de bază a unui set. $ set = funcție ($ element) return true;; $ this-> assertTrue ($ this-> funSets-> conține ($ set, 100));
Și înfășurați codul nostru de producție înăuntru FunSets.php
într-o clasă:
clasa FunSets funcția publică conține ($ set, $ elem) return $ set ($ elem);
Puteți executa de fapt acest test și acesta va trece. Setul pe care l-am definit pentru acest test este doar o funcție care întotdeauna revine la adevărat. Este un "set adevărat".
Dacă capitolul precedent a fost puțin confuz sau arătat inutil în logică, acesta o va clarifica puțin. Vrem să definim un set cu un singur element, un set singleton. Rețineți că aceasta trebuie să fie o funcție și că vom dori să o folosim ca în testul de mai jos.
function testSingletonSetContainsSingleElement () // Un set singleton este caracterizat printr-o functie care a trecut la continutul va reveni valabil pentru un singur element // trecut ca parametru. Cu alte cuvinte, un singleton este un set cu un singur element. $ singleton = $ this-> funSets-> singletonSet (1); $ this-> assertTrue ($ this-> funSets-> conține ($ singleton, 1));
Trebuie să definim o funcție numită "SingeltonSet"
cu un parametru care reprezintă un element al setului. În test, aceasta este numărul unu (1). Apoi ne așteptăm pe noi conține
atunci când este chemat cu o funcție singleton, să se întoarcă Adevărat
dacă parametrul trimis este egal cu unul. Codul care face testul este următorul:
functie publica singletonSet ($ elem) return function ($ otherElem) foloseste ($ elem) return $ elem == $ otherElem; ;
Wow! Asta e o nebunie. Deci, funcția "SingletonSet"
devine ca parametru un element ca $ elem
. Apoi returnează o altă funcție care are un parametru $ otherElem
iar această a doua funcție se va compara $ elem
la $ otherElem
.
Deci, cum funcționează acest lucru? În primul rând, această linie:
$ singleton = $ this-> funSets-> singletonSet (1);
este transformat în ceea ce "SingletonSet (1)"
se intoarce:
$ singleton = functie ($ otherElem) return 1 == $ otherElem; ;
Atunci "conține ($ singleton, 1)"
se numește. Care, la rândul său, numește tot ce este $ Singleton
. Deci, codul devine:
$ Singleton (1)
Care execută de fapt codul în el cu $ otherElem
având valoarea unu.
retur 1 == 1
Care este, desigur, adevărat și trece testul nostru.
Zâmbești deja? Crezi că creierul tău începe să fiarbă? Sigur că am făcut-o când am scris acest exemplu pentru Scala și am făcut din nou când am scris acest exemplu pentru prima dată în PHP. Cred că este extraordinar. Am reușit să definim un set, cu un element, cu capacitatea de a verifica dacă acesta conține valoarea pe care am trecut-o. Am făcut toate acestea fără o singură cesiune de valoare. Nu avem nici o variabilă care să conțină valoarea sau să aibă o stare de una. Nici o stare, nici o sarcină, nici o mutabilitate, nici o bucle. Suntem pe calea cea bună aici.
Acum, că putem crea un set cu o singură valoare, trebuie să putem crea un set cu mai multe valori. Modul evident de a face acest lucru este definirea operațiunii sindicale pe seturile noastre. Unirea a două seturi singleton va reprezenta o altă uniune cu ambele valori. Vreau să faceți o clipă și să vă gândiți la soluție înainte de a vă deplasa la cod, poate să faceți o apreciere a testelor de mai jos.
funcția testUnionContainsAllElements () // O uniune este caracterizată de o funcție care primește 2 seturi ca parametri și conține toate seturile furnizate // Putem crea doar singletons în acest moment, așa că noi creăm 2 singletons și le unim $ s1 = $ this -> funSets-> singletonSet (1); $ s2 = $ acest-> funSets-> singletonSet (2); $ union = $ this-> funSets-> uniune ($ s1, $ s2); // Acum, verificați că atât 1, cât și 2 fac parte din sindicatul $ this-> assertTrue ($ this-> funSets-> conține ($ union, 1)); $ this-> assertTrue ($ this-> funSets-> conține ($ union, 2)); // ... și că nu conține 3 $ this-> assertFalse ($ this-> funSets-> conține ($ union, 3));
Vrem o funcție numită "uniune"
care are doi parametri, ambele seturi. Amintiți-vă, seturile sunt doar funcții pentru noi, deci pentru noi "uniune"
funcția va primi două funcții ca parametri. Apoi, vrem să putem verifica „Conține“
dacă uniunea conține un element sau nu. Deci, ale noastre "uniune"
funcția trebuie să returneze o altă funcție „Conține“
poate utiliza.
($ s1, $ s2) funcția de returnare ($ otherElem) utilizează ($ s1, $ s2) retur $ this-> conține ($ s1, $ otherElem) || $ this-> conține ($ s2, $ otherElem); ;
Aceasta funcționează destul de bine. Și este perfect valabil chiar și atunci când unirea voastră este chemată cu o altă uniune plus un singurton. Se cheamă conține
în sine pentru fiecare parametru. Dacă este o uniune, ea va recurge. Este atat de simplu.
Putem aplica aceeași logică a linerului cu modificări minore pentru a obține următoarele două funcții importante care caracterizează un set: intersecția - conține doar elementele comune între două seturi - și diferența - conține numai acele elemente din primul set care nu fac parte din al doilea set.
($ s1, $ s2) $ s1, $ s2) funcția de returnare ($ otherElem) utilizează ($ s1, $ s2) return $ this-> conține ($ s1, $ otherElem) && $ this-> otherElem); ; funcția publică funcțională ($ s1, $ s2) funcția de returnare ($ otherElem) utilizează ($ s1, $ s2) return $ this-> conține ($ s1, $ otherElem) &&! $ this-> , $ otherElem); ;
Nu vă voi inunda codul de testare pentru aceste două metode. Testele sunt scrise și le poți verifica dacă te uiți în codul atașat.
Ei bine, acest lucru este un pic mai complicat, nu vom putea rezolva acest lucru cu o singură linie de cod. Un filtru este o funcție care utilizează doi parametri: un set și o funcție de filtrare. Aplică funcția de filtrare la un set și returnează un alt set care conține numai elementele care satisfac funcția de filtrare. Pentru a înțelege mai bine, aici este testul pentru aceasta.
funcția testFilterContainsOnlyElementsThatMatchConditionFunction () $ u12 = $ this-> createUnionWithElements (1, 2); $ u123 = $ this-> funSets-> uniune ($ u12, $ this-> funSets-> singletonSet (3)); // Regulă de filtrare, găsiți elemente mai mari de 1 (adică 2 și 3) $ condition = function ($ elem) return $ elem> 1;; // set filtrat $ filteredSet = $ this-> funSets-> filter ($ u123, $ condition); // Verificați că setul filtrat nu conține 1 $ this-> assertFalse ($ this-> funSets-> conține ($ filteredSet, 1), "Nu trebuie să conțină 1"); // Verificați că conține 2 și 3 $ this-> assertTrue ($ this-> funSets-> conține ($ filteredSet, 2), "Trebuie să conțină 2"); $ this-> assertTrue ($ this-> funSets-> conține ($ filteredSet, 3), "ar trebui să conțină 3"); funcția privată createUnionWithElements ($ elem1, $ elem2) $ s1 = $ this-> funSets-> singletonSet ($ elem1); $ s2 = $ acest-> funSets-> singletonSet ($ elem2); returnează $ this-> funSets-> union ($ s1, $ s2);
Creăm un set cu trei elemente: 1, 2, 3. Și îl plasăm în variabilă $ u123
astfel încât este ușor de identificat în testele noastre. Apoi definim o funcție pe care dorim să o aplicăm și o punem în test Stare $
. În cele din urmă, numim filtru pe site-ul nostru $ u123
setat cu Stare $
și plasați setul rezultat în $ filteredSet
. Apoi vom avea afirmații cu „Conține“
pentru a determina dacă setul arată cum vrem. Funcția noastră de stare este simplă, va reveni la adevărat dacă elementul este mai mare decât unul. Deci setul nostru final ar trebui să conțină numai valorile doi și trei, și asta verificăm în afirmațiile noastre.
funcția de returnare a funcției return ($ otherElem) ($ set, $ condition) if ($ condition ($ otherElem)) returnează $ this-> conține ($ set, $ otherElem); return false; ;
Și aici te duci. Am implementat filtrarea cu doar trei linii de cod. Mai precis, dacă condiția se aplică elementului furnizat, executăm un conținut pe set pentru acel element. Dacă nu, tocmai ne întoarcem fals
. Asta e.
Următorul pas este de a crea diferite funcții de buclă. Primul, "pentru toți()", va lua a $ set
și a Stare $
și întoarcere Adevărat
dacă Stare $
se aplică tuturor elementelor din $ set
. Aceasta conduce la următorul test:
funcția testForAllCorrectlyTellsIfAllElementsSatisfyCondition () $ u123 = $ this-> createUnionWith123 (); $ higherThanZero = funcție ($ elem) întoarcere $ elem> 0; ; $ higherThanOne = funcție ($ elem) return $ elem> 1; ; $ higherThanTwo = funcție ($ elem) întoarcere $ elem> 2; ; $ this-> assertTrue ($ acest-> funSets-> forall ($ u123, $ higherThanZero)); $ this-> assertFalse ($ acest-> funSets-> forall ($ u123, $ higherThanOne)); $ this-> assertFalse ($ acest-> funSets-> forall ($ u123, $ higherThanTwo));
Am extras-o $ u123
crearea de la testul anterior într-o metodă privată. Apoi definim trei condiții diferite: mai mari decât zero, mai mari decât una și mai mari decât două. Deoarece setul nostru conține numerele unu, doi și trei, numai condiția mai mare decât zero ar trebui să se întoarcă la adevărat, restul ar trebui să fie fals. Într-adevăr, putem trece testul cu ajutorul unei alte metode recursive care se utilizează pentru a itera peste toate elementele.
privat $ bound = 1000; funcția privată pentruallIterator ($ currentValue, $ set, $ condition) if ($ currentValue> $ this-> bound) returnează true; alt $ ($ this-> contains ($ set, $ currentValue)) returnează $ condition ($ currentValue) && $ this-> forallIterator ($ currentValue + 1, $ set, $ condition); altul returnează $ this-> forallIterator ($ currentValue + 1, $ set, $ condition); funcția publică forall ($ set, $ condition) retur $ this-> forallIterator (- $ this-> bound, $ set, $ condition);
Începem prin definirea unor limite pentru setul nostru. Valorile trebuie să fie între -1000 și +1000. Aceasta este o limitare rezonabilă pe care o impunem pentru a păstra acest exemplu destul de simplu. Functia "pentru toți"
va apela metoda privată "ForallIterator"
cu parametrii necesari pentru a decide în mod recursiv dacă toate elementele respectă starea. În această funcție, testăm mai întâi dacă suntem în afara limitelor. Dacă da, reveniți la adevărat. Apoi, verificați dacă setul nostru conține valoarea curentă și returnați valoarea curentă aplicată condiției împreună cu un logic "AND" cu un apel recursiv pentru noi înșine cu următoarea valoare. În caz contrar, trebuie doar să ne numim cu următoarea valoare și să returnăm rezultatul.
Acest lucru funcționează foarte bine, îl putem implementa în același mod ca și "Există ()"
. Aceasta se întoarce Adevărat
dacă oricare dintre ele îndeplinește condiția.
există o funcție privatăIterator ($ currentValue, $ set, $ condition) if ($ currentValue> $ this-> bound) return false; elseif ($ this-> conține ($ set, $ currentValue)) returnează $ condition ($ currentValue) || $ this-> existsIterator ($ curentValue + 1, set $, condiție $); altul returnează $ this-> existsIterator ($ currentValue + 1, $ set, $ condition); funcția publică există ($ set, $ condition) return $ this-> existsIterator (- $ this-> bound, $ set, $ condition);
Singura diferență este că ne întoarcem fals
atunci când ne aflăm în afara limitelor și folosim "OR" în loc de "ȘI" în a doua, dacă.
Acum, "Hartă()"
vor fi diferite, mai simple și mai scurte.
($ set, $ action) $ setE, $ action) $ setE, $ action) $ setE, $ action) returnați $ currentElem == $ action ($ elem);); ;
Cartografierea înseamnă că aplicăm o acțiune tuturor elementelor unui set. Pentru hartă, nu avem nevoie de iterator ajutător, putem reutiliza "Există ()"
și returnează acele elemente ale "există" care satisfac rezultatul acțiune $
aplicat $ element de
. Acest lucru poate să nu fie evident la primul loc, așa că să vedem ce se întâmplă.
1, 2
și acțiunea element $ * 2 (dublu)
pentru a cartografia.există
cu setul 1, 2
și funcția condiție $ currentElement
este egală $ elem * 2
.există ()
va itera peste toate elementele între -1000 și +1000, limitele noastre. Când găsește un element, dublu din ceea ce vine de la „Conține“
(valoarea a $ currentElement
) se va intoarce Adevărat
.Adevărat
pentru că apelul conține două valori, atunci când valoarea curentului înmulțită cu două, are două. Deci, pentru primul element al setului, unul, se va întoarce pe două. Pentru cel de-al doilea element, două, la valoarea patru. Programarea funcțională este distractivă dar este departe de a fi ideală în PHP. Deci, nu vă recomand să scrieți aplicații întregi în acest fel. Cu toate acestea, acum că ați învățat ce poate face PHP funcțional, puteți aplica părți din aceste cunoștințe în proiectele zilnice. Iată un exemplu de modul de autentificare. AuthPlugin
clasa oferă o metodă care primește un utilizator și o parolă și face magia să autentifice utilizatorul și să-și stabilească permisiunile.
clasa AuthPlugin private $ permissions = array (); funcția de autentificare ($ username, $ password) $ this-> verifyUser ($ username, $ password); $ adminModules = noi AdminModule (); $ this-> permisiuni [] = $ adminModules-> allowRead ($ username); $ this-> permisiuni [] = $ adminModules-> allowWrite ($ username); $ this-> permisiuni [] = $ adminModules-> allowExecute ($ username); funcția privată verifyUser ($ username, $ password) // ... UTILIZATOR / PASS CHECKING // ... DETALII DE UTILIZARE A UTILIZATORULUI, ETC.
Acum, s-ar putea să sune bine, dar are o mare problemă. 80% din "autentifica()"
metoda folosește informații de la "AdminModules"
. Aceasta creează o dependență foarte puternică.
Ar fi mult mai rezonabil să luați cele trei apeluri și să creați o singură metodă AdminModules
.
Deci, prin mutarea generației AdminModules
am reușit să reducem trei dependențe la doar unul. Interfața publică a AdminModules
a fost de asemenea redusă de la trei la o singură metodă. Cu toate acestea, nu suntem încă acolo. AuthPlugin
încă direct depinde de AdminModules
.
Dacă doriți ca pluginul nostru de autentificare să fie utilizat de orice modul, trebuie să definim o interfață comună pentru aceste module. Să injectăm dependența și să introducem o interfață.
clasa AuthPlugin private $ permissions = array (); privat $ appModule; funcția __construct (ApplicationModule $ appModule) $ this-> appModule = $ appModule; autentifică funcția ($ username, $ password) $ this-> verifyUser ($ username, $ password); $ this-> permissions = array_merge ($ this-> permisiuni, $ this-> appModule-> getPermissions ($ username)); funcția privată verifyUser ($ username, $ password) // ... UTILIZATOR / PASS CHECKING // ... DETALII DE UTILIZARE A UTILIZATORULUI, ETC.
AuthPlugin
a primit un constructor. Ea devine un parametru de tip ApplicationModule
, o interfață și apeluri "getPermissions ()"
pe acest obiect injectat.
interfață ApplicationModule funcția publică getPermissions ($ username);
ApplicationModule
definește o singură metodă publică, "getPermissions ()"
, cu un nume de utilizator ca parametru.
class AdminModules implementează ApplicationModule // [...]
In cele din urma, AdminModules
trebuie să pună în aplicare ApplicationModule
interfață.
Acum, este mult mai bine. Al nostru AuthPlugin
depinde numai de o interfață. AdminModules
depinde de aceeași interfață, astfel încât AuthPlugin
a devenit modul agnostic. Putem crea orice număr de module, toate punerea în aplicare ApplicationModule
, și AuthPlugin
va fi capabil să lucreze cu toți.
O altă modalitate de a inversa dependența și de a face AdminModule
, sau orice alt modul, pentru a utiliza AuthPlugin
este de a injecta în aceste module o dependență de AuthPlugin
. AuthPlugin
va oferi o modalitate de a seta funcția de autentificare și fiecare aplicație va trimite în propriile sale "GetPermission ()"
funcţie.
clasa AdminModules private $ authPlugin; funcția __construct (Authentitcation $ authPlugin) $ this-> authPlugin = $ authPlugin; funcția privată allowRead ($ username) return "yes"; funcția privată allowWrite ($ username) return "no"; funcția privată allowExecute ($ username) return $ username == "joe"? "da nu"; funcția privată authenticate () $ this-> authPlugin-> setPermissions (funcția ($ username) $ permissions = array (); $ permissions [] = $ this-> allowRead ($ username); acest lucru-> allowWrite ($ username); $ permissions [] = $ this-> allowExecute ($ username); return $ permisiuni;); $ This-> authPlugin-> autentifice ();
Începem cu AdminModule
. Nu mai pune în aplicare nimic. Cu toate acestea, utilizează un obiect injectat care trebuie să implementeze autentificarea. În AdminModule
va exista un "autentifica()"
metoda care va suna "setPermissions ()"
pe AuthPlugin
și treci în funcția care trebuie utilizată.
interfata Autentificare function setPermissions ($ permissionGrantingFunction); funcția authenticate ();
Interfața de autentificare definește pur și simplu cele două metode.
class AuthPlugin implementează autentificarea private $ permissions = array (); privat $ appModule; privat $ permissionsFunction; funcția __construct (ApplicationModule $ appModule) $ this-> appModule = $ appModule; autentifică funcția ($ username, $ password) $ this-> verifyUser ($ username, $ password); $ this-> permissions = $ this-> permissionsFunction ($ username); funcția privată verifyUser ($ username, $ password) // ... UTILIZATOR / PASS CHECKING // ... DETALII DE UTILIZARE A UTILIZATORULUI, ETC. funcția publică setPermissions ($ permissionGrantingFunction) $ this-> permissionsFunction = $ permissionGrantingFunction;
In cele din urma, AuthPlugin
implementează autentificarea și stabilește funcția de intrare într-un atribut de clasă privată. Atunci, "autentificare()"
devine o metodă proastă. Apel doar la funcție și apoi stabilește valoarea returnată. Este complet decuplat de orice se întâmplă.
Dacă ne uităm la schemă, există două schimbări importante:
AdminModule
, AuthPlugin
este cea care implementează interfața.AuthPlugin
va "apela înapoi" AdminModule
, sau orice alt modul trimis în funcția de permisiuni.Nu există un răspuns corect la această întrebare. Aș susține că, dacă procesul de determinare a permisiunilor este destul de dependent de modulul de aplicare, atunci abordarea orientată spre obiect este mai potrivită. Cu toate acestea, dacă credeți că fiecare modul de aplicație ar trebui să poată furniza o funcție de autentificare, și dvs. AuthPlugin
este doar un schelet care oferă funcționalitatea de autentificare, dar fără să știe nimic despre utilizatori și proceduri, atunci puteți merge cu abordarea funcțională.
Abordarea funcțională vă face AuthPlugin
foarte abstractă și puteți depinde de ea. Cu toate acestea, dacă intenționați să vă permiteți AuthPlugin
să faceți mai mult și să aflați mai multe despre utilizatori și sistemul dvs., atunci acesta va deveni prea concret și nu doriți să vă depindeți de el. În acest caz, alegeți modul orientat spre obiect și lăsați betonul AuthPlugin
depind de modulele de aplicație mai abstracte.