En nybegynners guide til designmønstre

Noen gang lurt på hva designmønstre er? I denne artikkelen vil jeg forklare hvorfor designmønstre er viktige, og vil gi noen eksempler, i PHP, når og hvorfor de skal brukes.


Hva er designmønstre?

Designmønstre er optimaliserte, gjenbrukbare løsninger på programmeringsproblemene vi møter hver dag. Et mønster er ikke en klasse eller et bibliotek som vi bare kan plugge inn i vårt system; det er mye mer enn det. Det er en mal som må implementeres i riktig situasjon. Det er heller ikke språkspesifikt. Et godt designmønster bør kunne implementeres på de fleste, om ikke alle språk, avhengig av språkets evner. Viktigst av alt, kan ethvert designmønster være et dobbeltkantet sverd - hvis det er implementert på feil sted, kan det være katastrofalt og skape mange problemer for deg. Men implementert på rett sted, til rett tid, kan det være din frelser.

Det er tre grunnleggende typer designmønstre:

  • strukturell
  • creational
  • atferds

Strukturell mønstre handler generelt om relasjoner mellom enheter, noe som gjør det lettere for disse enhetene å jobbe sammen.

creational mønstre gir instantiation mekanismer, noe som gjør det lettere å lage objekter på en måte som passer til situasjonen.

Behavioral mønstre brukes i kommunikasjon mellom enheter og gjør det lettere og mer fleksibelt for disse enhetene å kommunisere.

Hvorfor skal vi bruke dem?

Designmønstre er, etter prinsipp, godt gjennomtenkte løsninger på programmeringsproblemer. Mange programmerere har møtt disse problemene før, og har brukt disse "løsningene" for å avhjelpe dem. Hvis du støter på disse problemene, hvorfor gjenskape en løsning når du kan bruke et allerede bevist svar?

Eksempel

La oss forestille deg at du har fått ansvaret for å skape en måte å slå sammen to klasser som gjør to forskjellige ting basert på situasjonen. Disse to klassene brukes sterkt av det eksisterende systemet på forskjellige steder, noe som gjør det vanskelig å fjerne disse to klassene og endre eksisterende kode. For å legge til dette, krever endring av eksisterende kode at du også må teste noen endret kode, siden disse typer redigeringer, i et system som er avhengig av forskjellige komponenter, nesten alltid introduserer nye feil. I stedet for å gjøre dette, kan du implementere en variasjon av strategimønsteret og adaptermønsteret, som lett kan håndtere disse typer scenarier.

_context = $ context;  offentlig funksjon operasjon1 () hvis ($ dette -> _ kontekst == "context_for_class_one") $ dette -> _ class_one-> drift1_in_class_one_context ();  ellers ($ this -> _ context == "context_for_class_two") $ dette -> _ class_two-> drift1_in_class_two_context (); 

Ganske enkelt, ikke sant? Nå, la oss ta en nærmere titt på strategimønsteret.


Strategimønster


Bilde med lov av http://cioinnervoice.wordpress.com

De strategi mønster er et adferdsmønster som gjør det mulig å bestemme hvilken handlingsplan et program skal ta, basert på en bestemt kontekst under kjøretid. Du innkapsler to forskjellige algoritmer i to klasser, og bestemmer deg for kjøretid som strategi du vil gå med.

I vårt eksempel ovenfor er strategien basert på hva som helst $ sammenheng variabel var på det tidspunktet klassen ble instantiated. Hvis du gir den sammenhengen for class_one, den vil bruke class_one og vice versa.

Søt, men hvor kan jeg bruke dette?

Tenk deg at du for tiden utvikler en klasse som enten kan oppdatere eller opprette en ny brukeroppføring. Den trenger fortsatt de samme inngangene (navn, adresse, mobilnummer osv.), Men avhengig av en gitt situasjon, må den bruke forskjellige funksjoner når man oppdaterer og oppretter. Nå kan du sannsynligvis bare bruke en if-else for å oppnå dette, men hva om du trenger å bruke denne klassen på et annet sted? I så fall må du omskrive den samme if-else-setningen igjen. Ville det ikke være enklere å bare spesifisere konteksten din?

 

Nå innebærer det "vanlige" strategimønsteret innkapsling av algoritmer i en annen klasse, men i dette tilfellet ville en annen klasse være sløsing. Husk at du ikke trenger å følge malen nøyaktig. Variasjoner fungerer så lenge konseptet forblir det samme, og det løser problemet.


Adapter Mønster


Bilde med lov av http://www.uxcell.com

De adapter mønster er et strukturelt designmønster som gjør at du kan omplassere en klasse med et annet grensesnitt, slik at det kan brukes av et system som bruker forskjellige anropsmetoder.

Dette lar deg også endre noen av inngangene som mottas fra klientklassen, noe som gjør det til noe som er kompatibelt med adapteens funksjoner.

Hvordan kan jeg bruke dette?

Et annet begrep som refererer til en adapterklasse er a wrapper, som i utgangspunktet lar deg "pakke" handlinger inn i en klasse og gjenbruk disse handlingene i de riktige situasjonene. Et klassisk eksempel kan være når du lager en domeneklasse for tabellklasser. I stedet for å ringe de forskjellige tabellklassene og kalle opp funksjonene en etter en, kan du inkapslere alle disse metodene i en metode ved hjelp av en adapterklasse. Dette vil ikke bare tillate deg å gjenbruke hvilken handling du vil, det holder deg også fra å måtte omskrive koden hvis du må bruke den samme handlingen på et annet sted.

Sammenlign disse to implementasjonene.

Ikke-adapter-tilnærming

CreateOrUpdate (// innganger); $ profile = ny profil (); $ profile-> CreateOrUpdate (// inputs);

Hvis vi trengte å gjøre dette igjen på et annet sted, eller til og med bruke denne koden i et annet prosjekt, måtte vi skrive alt om igjen.

Bedre

Det står i motsetning til å gjøre noe slikt:

NewAccount (// innganger);

I denne situasjonen har vi en innpakningsklasse, som vil være vår konto domeneklasse:

CreateOrUpdate (// delmengde av innganger); $ profile = ny profil (); $ profile-> CreateOrUpdate (// delmengde av innganger); 

På denne måten kan du bruke kontodomenet ditt igjen når du trenger det, pluss at du kan pakke inn andre klasser under domeneklassen din også.


Fabrikk Metode Mønster


Bilde med lov av http://www.lankanewspappers.com

De fabrikk metode mønster er et kreasjonsdesign mønster som gjør akkurat som det høres ut: det er en klasse som fungerer som en fabrikk med objektfelter.

Hovedmålet med dette mønsteret er å inkapslere skapelsesprosedyren som kan spenne forskjellige klasser inn i en enkelt funksjon. Ved å gi riktig kontekst til fabrikkmetoden, vil den kunne returnere det riktige objektet.

Når kan jeg bruke dette?

Den beste tiden å bruke fabrikkmetoden er når du har flere forskjellige varianter av en enkelt enhet. La oss si at du har en knappeklasse; denne klassen har forskjellige variasjoner, for eksempel ImageButton, InputButton og FlashButton. Avhengig av sted, må du kanskje opprette forskjellige knapper. Dette er hvor du kan bruke en fabrikk til å lage knappene for deg!

La oss begynne med å lage våre tre klasser:

_html;  klasse ImageButton utvider knapp protected $ _html = "..."; // Dette bør være hva HTML du vil ha for din bildebaserte knapp ► klasse InputButton utvider Button protected $ _html = "..."; // Dette bør være hva HTML du vil ha for din normale knapp ();  klasse FlashButton utvider knapp protected $ _html = "..."; // Dette bør være hva HTML du vil ha for din flash-baserte knapp

Nå kan vi lage vår fabrikk klasse:

 

Vi kan bruke denne koden slik:

$ knapper = array ('image', 'input', 'flash'); foreach ($ knapper som $ b) echo ButtonFactory :: createButton ($ b) -> getHtml ()

Utgangen bør være HTML for alle knapptypene dine. På denne måten vil du kunne spesifisere hvilken knapp som skal opprettes avhengig av situasjonen og gjenbruk tilstanden også.


Dekoratormønster


Bilde med lov av http://www.decoratorsdarlington.co.uk

De dekoratør mønster er et strukturelt designmønster som gjør det mulig for oss å legge til ny eller ekstra oppførsel til et objekt under kjøretid, avhengig av situasjonen.

Målet er å gjøre det slik at de utvidede funksjonene kan brukes på en bestemt forekomst, og samtidig kan man fremdeles opprette en originaleksempel som ikke har de nye funksjonene. Det gjør det også mulig å kombinere flere dekoratører for en forekomst, slik at du ikke sitter fast med en dekoratør for hver forekomst. Dette mønsteret er et alternativ til underklasse, som refererer til å skape en klasse som arver funksjonalitet fra en forelderklasse. I motsetning til subclassing, som legger oppførelsen på kompileringstid, kan "dekorere" legge til ny oppførsel i løpet av runtime, hvis situasjonen krever det.

For å implementere dekoratormønsteret kan vi følge disse trinnene:

  1. Subclass den opprinnelige "Component" -klassen til en "Decorator" -klasse
  2. I Decorator-klassen legger du til en komponentpeker som et felt
  3. Pass en komponent til dekoratorkonstruktøren for å initialisere komponentpekeren
  4. I Decorator-klassen, omdirigere alle "Component" -metoder til "Component" -pekeren, og
  5. I Decorator-klassen, overstyr enhver komponentmetode (e) hvis oppførsel må endres

Trinn med hilsen http://en.wikipedia.org/wiki/Decorator_pattern

Når kan jeg bruke dette?

Det beste stedet å bruke dekoratormønsteret er når du har en enhet som bare trenger ny oppførsel hvis situasjonen krever det. La oss si at du har et HTML-koblingselement, en logout-kobling, som du vil gjøre litt forskjellige ting, basert på den nåværende siden. For det kan vi bruke dekoratormønsteret.

Først, la oss etablere de forskjellige "dekorasjonene" vi trenger.

  • Hvis vi er på hjemmesiden og logget inn, må denne lenken pakkes inn i h2-koder
  • Hvis vi er på en annen side og logget inn, må denne lenken pakkes inn understrekkskoder
  • Hvis vi er logget inn, har denne linken pakket inn i sterke koder

Når vi har etablert våre dekorasjoner, kan vi begynne å programmere dem.

_html = "Logg ut";  offentlig funksjon setHtml ($ html) $ this -> _ html = $ html;  offentlig funksjon gjengivelse () echo $ this -> _ html;  klasse LogoutLinkH2Decorator utvider HtmlLinks protected $ _logout_link; offentlig funksjon __construct ($ logout_link) $ this -> _ logout_link = $ logout_link; $ Dette-> setHtml ("

". $ this -> _ html."

"); offentlig funksjon __call ($ navn, $ args) $ dette -> _ logout_link -> $ navn ($ args [0]); klasse LogoutLinkUnderlineDecorator utvider HtmlLinks protected $ _logout_link; offentlig funksjon __construct ($ logout_link) $ this -> _ logout_link = $ logout_link; $ this-> setHtml ("". $ this -> _ html.""); offentlig funksjon __call ($ navn, $ args) $ dette -> _ logout_link -> $ navn ($ args [0]); klasse LogoutLinkStrongDecorator utvider HtmlLinks protected $ _logout_link; offentlig funksjon __construct ($ logout_link) $ this -> _ logout_link = $ logout_link; $ this-> setHtml ("". $ this -> _ html.""); offentlig funksjon __call ($ navn, $ args) $ dette -> _ logout_link -> $ navn ($ args [0]);

Vi burde da kunne bruke det slik:

$ logout_link = ny LogoutLink (); hvis ($ is_logged_in) $ logout_link = ny LogoutLinkStrongDecorator ($ logout_link);  hvis ($ in_home_page) $ logout_link = ny LogoutLinkH2Decorator ($ logout_link);  else $ logout_link = ny LogoutLinkUnderlineDecorator ($ logout_link);  $ logout_link-> render ();

Vi kan se her hvordan vi kan kombinere flere dekoratører hvis vi trenger dem. Siden alle dekoratørene bruker __anrop magisk funksjon, kan vi fortsatt kalle den opprinnelige funksjonens metoder. Hvis vi antar at vi for tiden er inne på hjemmesiden og logget inn, bør HTML-utgangen være:

Logg ut


Singleton Pattern


Bilde med lov av http://intoxicologist.wordpress.com

De singleton designmønsteret er et kreasjonsdesignmønster som sørger for at du har en enkelt forekomst av en bestemt klasse i løpet av din kjøretid, og gir et globalt punkt for tilgang til enkelteksemplaret.

Dette gjør det lettere å sette opp et punkt for "koordinering" for andre objekter som også bruker singleton-forekomsten, siden singleton-variablene alltid vil være det samme for alt som kaller det.

Når kan jeg bruke dette?

Hvis du trenger å sende en bestemt forekomst fra en klasse til en annen, kan du bruke singleton-mønsteret for å unngå å måtte passere forekomsten via konstruktør eller argument. Tenk deg at du har opprettet en sesjonsklasse, som simulerer $ _SESSION global array. Siden denne klassen bare trenger å bli instantiated en gang, kan vi implementere et singleton mønster som dette:

 

Ved å gjøre dette, kan vi få tilgang til vår økteksempel fra forskjellige deler av koden, selv i forskjellige klasser. Disse dataene vil fortsette gjennom alle getInstance-samtaler.


Konklusjon

Det er mange flere designmønstre å studere; I denne artikkelen har jeg bare fremhevet noen av de mer fremtredende som jeg bruker når du programmerer. Hvis du er interessert i å lese om de andre designmønstrene, har Wikipedias Design Patterns-side en mengde informasjon. Hvis det ikke er nok, kan du alltid sjekke ut Designmønstre: Elementer av gjenbrukbar objektorientert programvare, som anses å være en av de beste designmønsterbøkene som er tilgjengelige.

En siste ting: når du bruker disse designmønstrene, ALWays sørg for at du prøver å løse det riktige problemet. Som nevnt tidligere, er disse mønstrene et dobbeltkantsverd: hvis de brukes i feil sammenheng, kan de potensielt gjøre ting verre; men hvis de brukes riktig, blir de uunnværlige.

Hvis du fant denne opplæringen nyttig, hvorfor ikke sjekke ut omfanget av PHP-skript på Envato Market. Det er tusenvis av nyttige skript som kan fremskynde utviklingen din og hjelpe deg med å oppnå bedre sluttresultat. Du kan finne bestillingssystemer, AJAX-kontaktskjemaer, nyhetsbrevsystemer og mye mer. 

PHP-skript på Envato Market