I objektorientert programmering er polymorfisme et kraftig og grunnleggende verktøy. Det kan brukes til å skape en mer organisk strøm i søknaden din. Denne opplæringen beskriver det generelle begrepet polymorfisme, og hvordan det enkelt kan distribueres i PHP.
Polymorfisme er et langt ord for et veldig enkelt konsept.
Polymorfisme beskriver et mønster i objektorientert programmering i hvilke klasser har forskjellig funksjonalitet mens de deler et felles grensesnitt.
Den vakre polymorfismen er at koden som arbeider med de forskjellige klassene ikke trenger å vite hvilken klasse den bruker siden de alle brukes på samme måte.
En ekte verdensanalyse for polymorfisme er en knapp. Alle vet hvordan man bruker en knapp: du bruker bare trykk på den. Hva en knapp "gjør", avhenger imidlertid av hva den er knyttet til og konteksten der den brukes - men resultatet påvirker ikke hvordan det brukes. Hvis sjefen din forteller deg å trykke på en knapp, har du allerede all den informasjonen som trengs for å utføre oppgaven.
I programmeringsverdenen brukes polymorfisme til å gjøre applikasjoner mer modulære og utvidbare. I stedet for rotete betingede utsagn som beskriver ulike handlingsmåter, oppretter du utskiftbare objekter du velger basert på dine behov. Det er det grunnleggende målet med polymorfisme.
En integrert del av polymorfismen er det felles grensesnittet. Det er to måter å definere et grensesnitt på i PHP: grensesnitt og abstrakte klasser. Begge har sine bruksområder, og du kan blande og matche dem slik du ser det passer i klassenes hierarki.
Et grensesnitt ligner en klasse bortsett fra at den ikke kan inneholde kode. Et grensesnitt kan definere metodenavn og argumenter, men ikke innholdet i metodene. Eventuelle klasser som implementerer et grensesnitt må implementer alle metoder definert av grensesnittet. En klasse kan implementere flere grensesnitt.
Et grensesnitt er erklært ved å bruke 'grensesnitt
'søkeord:
grensesnitt MyInterface // methods
og er festet til en klasse ved å bruke 'redskaper
'søkeord (flere grensesnitt kan implementeres ved å oppgi dem skilt med kommaer):
klassen MyClass implementerer MyInterface // methods
Metoder kan defineres i grensesnittet akkurat som i en klasse, unntatt uten kroppen (delen mellom bøylene):
grensesnitt MyInterface public function doThis (); offentlig funksjon doThat (); offentlig funksjon settnavn ($ navn);
Alle metoder definert her må inkluderes i noen implementeringsklasser nøyaktig som beskrevet. (les koden kommentarer nedenfor)
// Gyldig klasse MyClass implementerer MyInterface protected $ name; offentlig funksjon gjør dette () // kode som gjør dette offentlig funksjon doThat () // kode som gjør det offentlig funksjon setName ($ navn) $ this-> name = $ name; // INVALID klasse MyClass implementerer MyInterface // missing doThis ()! privat funksjon doThat () // dette burde være offentlig! offentlige funksjon setName () // mangler navnet argumentet!
En abstrakt klasse er en blanding mellom et grensesnitt og en klasse. Det kan definere funksjonalitet så vel som grensesnitt (i form av abstrakte metoder). Klasser som utvider en abstrakt klasse må implementer alle abstrakte metoder definert i abstrakt klassen.
En abstrakt klasse er erklært på samme måte som klasser med tillegg av "abstrakt
'søkeord:
abstrakt klasse MyAbstract // methods
og er festet til en klasse ved å bruke 'strekker
'søkeord:
klassen MyClass utvider MyAbstract // klassemetoder
Vanlige metoder kan defineres i en abstrakt klasse, akkurat som i en vanlig klasse, samt noen abstrakte metoder (ved hjelp av "abstrakt
'søkeord). Abstrakte metoder oppfører seg akkurat som metoder definert i et grensesnitt, og må implementeres nøyaktig som definert ved å utvide klasser.
abstrakt klasse MyAbstract public $ name; offentlig funksjon gjør dette () // gjør dette abstrakt offentlig funksjon doThat (); abstrakt offentlig funksjon setName ($ navn);
La oss forestille deg at du har en Artikkel
klasse som er ansvarlig for å håndtere artikler på nettstedet ditt. Den inneholder informasjon om en artikkel, inkludert tittelen, forfatteren, datoen og kategorien. Slik ser det ut:
klasse poly_base_Article public $ title; offentlig $ forfatter; offentlig $ dato; offentlig $ kategori; offentlig funksjon __construct ($ title, $ author, $ date, $ category = 0) $ this-> title = $ title; $ this-> author = $ author; $ this-> date = $ date; $ this-> category = $ category;
Merk: Eksempelklassene i denne opplæringen bruker navngivningskonvensjonen av "package_component_Class." Dette er en vanlig måte å skille klasser i virtuelle navneområder for å unngå navnekollisjoner.
Nå vil du legge til en metode for å sende informasjonen til forskjellige formater, for eksempel XML og JSON. Du kan bli fristet til å gjøre noe slikt:
klasse poly_base_Article // ... public function write ($ type) $ ret = "; bytt ($ type) case 'XML': $ ret = ''; $ ret. = ' '; gå i stykker; sak 'JSON': $ array = array ('article' => $ obj); $ ret = json_encode ($ array); gå i stykker; returner $ ret;'. $ obj-> tittel. ' '; $ ret. = ''. $ obj-> forfatter. ' '; $ ret. = ''. $ obj-> dato. ' '; $ ret. = ''. $ obj-> kategori. ' '; $ ret. = '
Dette er litt av en stygg løsning, men det fungerer - for nå. Spør deg selv hva som skjer i fremtiden, men når vi vil legge til flere formater? Du kan fortsette å redigere klassen, legge til flere og flere tilfeller, men nå fortykker du bare klassen din.
Et viktig prinsipp for OOP er at en klasse skal gjøre en ting, og det skal gjøre det bra.
Med dette i tankene bør betingede utsagn være et rødt flagg som indikerer at klassen din prøver å gjøre for mange forskjellige ting. Det er her polymorfisme kommer inn.
I vårt eksempel er det klart at det presenteres to oppgaver: Administrere artikler og formatere deres data. I denne opplæringen vil vi refactor vår formateringskode inn i et nytt sett med klasser og oppdage hvor enkelt det er bruk polymorfisme.
Det første vi bør gjøre er å definere grensesnittet. Det er viktig å tenke hardt om grensesnittet ditt, fordi eventuelle endringer i det kan kreve endringer i ringekoden. I vårt eksempel bruker vi et enkelt grensesnitt for å definere vår ene metode:
grensesnitt poly_writer_Writer public function write (poly_base_Article $ obj);
Det er så enkelt; Vi har definert et publikum skrive()
metode som aksepterer et artikkelobjekt som et argument. Eventuelle klasser som implementerer Writer-grensesnittet, er sikker på å ha denne metoden.
Tips: Hvis du vil begrense hvilken type argumenter som kan overføres til dine funksjoner og metoder, kan du bruke type tips som vi har gjort i skrive()
metode; det aksepterer bare objekter av typen poly_base_Article
. Dessverre er returtypespenning ikke støttet i gjeldende versjoner av PHP, så det er opp til deg å ta vare på returverdier.
Med grensesnittet ditt definert, er det på tide å lage klassene som faktisk gjør ting. I vårt eksempel har vi to formater som vi vil sende ut. Dermed har vi to Writer-klasser: XMLWriter og JSONWriter. Det er opp til disse å trekke ut dataene fra det bestått artikkelen objektet og formatere informasjonen.
Slik ser XMLWriter ut:
klasse poly_writer_XMLWriter implementerer poly_writer_Writer public function write (poly_base_Article $ obj) $ ret = ''; $ ret. = ' '; returner $ ret;'. $ obj-> tittel. ' '; $ ret. = ''. $ obj-> forfatter. ' '; $ ret. = ''. $ obj-> dato. ' '; $ ret. = ''. $ obj-> kategori. ' '; $ ret. = '
Som du kan se fra klassedeklarasjonen, bruker vi redskaper
søkeord for å implementere grensesnittet vårt. De skrive()
Metoden inneholder funksjonalitet som er spesifikk for formatering av XML.
Nå er vår JSONWriter-klasse:
klasse poly_writer_JSONWriter implementerer poly_writer_Writer public function write (poly_base_Article $ obj) $ array = array ('article' => $ obj); return json_encode ($ array);
All vår kode som er spesifikk for hvert format, finnes nå i individuelle klasser. Disse klassene har det ene ansvar for å håndtere et bestemt format, og ingenting annet. Ingen annen del av søknaden din trenger å bry deg om hvordan disse fungerer for å kunne bruke den, takket være vårt grensesnitt.
Med våre nye klasser definert, er det på tide å besøke vår artikkelklasse. Alle koden som levde i originalen skrive()
Metoden er blitt utdelt i vårt nye sett med klasser. Alt vår metode må gjøre nå er å bruke de nye klassene, slik:
klasse poly_base_Article // ... public function skrive (poly_writer_Writer $ writer) return $ writer-> skriv ($ dette);
Alt denne metoden er nå akseptert et objekt av Writer-klassen (det er hvilken klasse som implementerer Writer-grensesnittet), ring det skrive()
metode, passerer seg selv ($ dette
) som argumentet, og send deretter returverdien direkte til klientkoden. Det trenger ikke lenger å bekymre seg om detaljene for formatering av data, og det kan fokusere på hovedoppgaven.
Du lurer kanskje på hvor du får et Writer-objekt til å begynne med, siden du må passere en til denne metoden. Det er opp til deg, og det er mange strategier. For eksempel kan du bruke en fabrikkklasse til å hente forespørseldata og opprette et objekt:
klasse poly_base_Factory offentlig statisk funksjon getWriter () // grab request variable $ format = $ _REQUEST ['format']; // Konstruer vårt klassenavn og kontroller eksistensen $ class = 'poly_writer_'. $ format. 'Forfatter'; hvis (class_exists ($ class)) // returner et nytt Writer-objekt returner ny $ class (); // ellers lykkes det ikke å kaste ny unntak ('Unsupported format');
Som jeg sa, er det mange andre strategier å bruke, avhengig av dine krav. I dette eksemplet velger en forespørselsvariabel hvilket format som skal brukes. Den konstruerer et klassenavn fra forespørselsvariabelen, kontrollerer om den eksisterer, og returnerer deretter et nytt Writer-objekt. Hvis ingen finnes under det navnet, kastes et unntak for å la klientkode finne ut hva du skal gjøre.
Med alt på plass, her er hvordan vår klientkode vil sette alt sammen:
$ article = new poly_base_Article ('Polymorphism', 'Steve', tid (), 0); prøv $ writer = poly_base_Factory :: getWriter (); fangst (Unntak $ e) $ writer = ny poly_writer_XMLWriter (); ekko $ artikkel-> skriv ($ forfatter);
Først opprettet vi et eksempel Artikkelobjekt å jobbe med. Da prøver vi å få et Writer-objekt fra fabrikken, som faller tilbake til en standard (XMLWriter) hvis et unntak kastes. Endelig sender vi Writer-objektet til vår artikkel skrive()
metode, utskrift av resultatet.
I denne opplæringen har jeg gitt deg en introduksjon til polymorfisme og en forklaring av grensesnitt i PHP. Jeg håper du skjønner at jeg bare har vist deg en potensiell brukstilfelle for polymorfisme. Det er mange, mange flere applikasjoner. Polymorfisme er en elegant måte å unnslippe fra stygge betingede utsagn i OOP-koden. Det følger prinsippet om å holde komponentene separate, og er en integrert del av mange designmønstre. Hvis du har noen spørsmål, ikke nøl med å spørre i kommentarene!