Een beginnershandleiding voor ontwerppatronen

Ooit afgevraagd wat ontwerppatronen zijn? In dit artikel zal ik uitleggen waarom ontwerppatronen belangrijk zijn en enkele voorbeelden geven in PHP over wanneer en waarom ze moeten worden gebruikt.


Wat zijn ontwerppatronen?

Ontwerppatronen zijn geoptimaliseerde, herbruikbare oplossingen voor de programmeerproblemen die we dagelijks tegenkomen. Een ontwerppatroon is geen klas of een bibliotheek die we gewoon in ons systeem kunnen pluggen; het is veel meer dan dat. Het is een sjabloon dat in de juiste situatie moet worden geïmplementeerd. Het is ook niet taalspecifiek. Een goed ontwerppatroon moet implementeerbaar zijn in de meeste, zo niet alle talen, afhankelijk van de mogelijkheden van de taal. Het belangrijkste is dat elk ontwerppatroon een tweesnijdend zwaard kan zijn - als het op de verkeerde plaats wordt geïmplementeerd, kan het rampzalig zijn en veel problemen voor u creëren. Echter, geïmplementeerd op de juiste plaats, op het juiste moment, kan het uw redder zijn.

Er zijn drie basistypen ontwerppatronen:

  • structureel
  • creational
  • gedragsmatig

Structureel patronen hebben meestal te maken met relaties tussen entiteiten, waardoor deze entiteiten gemakkelijker kunnen samenwerken.

Creational patronen voorzien in instantiemechanismen, waardoor het gemakkelijker wordt om objecten te maken op een manier die past bij de situatie.

Gedragsmatig patronen worden gebruikt in communicatie tussen entiteiten en maken het eenvoudiger en flexibeler voor deze entiteiten om te communiceren.

Waarom zouden we ze gebruiken??

Ontwerppatronen zijn principieel doordachte oplossingen voor programmeerproblemen. Veel programmeurs zijn al eerder met deze problemen geconfronteerd en hebben deze 'oplossingen' gebruikt om ze te verhelpen. Als u deze problemen ondervindt, waarom een ​​oplossing opnieuw maken wanneer u een reeds bewezen antwoord kunt gebruiken?

Voorbeeld

Laten we ons voorstellen dat je de verantwoordelijkheid hebt gekregen om een ​​manier te creëren om twee klassen samen te voegen die twee verschillende dingen doen die op de situatie zijn gebaseerd. Deze twee klassen worden op verschillende plaatsen door het bestaande systeem zwaar gebruikt, waardoor het moeilijk is om deze twee klassen te verwijderen en de bestaande code te wijzigen. Om dit toe te voegen, vereist het wijzigen van de bestaande code dat u ook elke gewijzigde code moet testen, aangezien dit soort bewerkingen, in een systeem dat afhankelijk is van verschillende componenten, bijna altijd nieuwe fouten introduceren. In plaats van dit te doen, kunt u een variatie van het strategiepatroon en het adapterpatroon implementeren, die gemakkelijk met dit soort scenario's kan omgaan.

_context = $ context;  public function operation1 () if ($ this -> _ context == "context_for_class_one") $ this -> _ class_one-> operation1_in_class_one_context ();  else ($ this -> _ context == "context_for_class_two") $ this -> _ class_two-> operation1_in_class_two_context (); 

Best simpel, toch? Laten we nu eens het strategiepatroon eens nader bekijken.


Strategiepatroon


Afbeelding met dank aan http://cioinnervoice.wordpress.com

De strategiepatroon is een gedragsmatig ontwerppatroon waarmee u kunt beslissen welke actie moet worden ondernomen op basis van een specifieke context tijdens runtime. U kapselt in twee klassen twee verschillende algoritmen in en bepaalt tijdens runtime welke strategie je wilt meegaan.

In ons bovenstaande voorbeeld is de strategie gebaseerd op wat dan ook $ context variabele was op het moment dat de klasse werd geïnstantieerd. Als je het de context voor geeft class_one, het gebruikt class_one, en omgekeerd.

Leuk, maar waar kan ik dit gebruiken?

Stel u voor dat u momenteel een klasse ontwikkelt die een nieuw gebruikersrecord kan bijwerken of maken. Het heeft nog steeds dezelfde ingangen nodig (naam, adres, mobiel nummer, enz.), Maar afhankelijk van een bepaalde situatie moet het verschillende functies gebruiken bij het bijwerken en creëren. Nu zou je waarschijnlijk een if-else kunnen gebruiken om dit te bereiken, maar wat als je deze les op een andere plaats moet gebruiken? In dat geval moet je dezelfde if-else-verklaring helemaal opnieuw herschrijven. Zou het niet eenvoudiger zijn om gewoon uw context te specificeren?

 

Nu, het "gebruikelijke" strategiepatroon houdt in dat je je algoritmen inkapselt in een andere klasse, maar in dit geval zou een andere klasse verspilling zijn. Vergeet niet dat u de sjabloon niet exact hoeft te volgen. Variaties werken zolang het concept hetzelfde blijft, en het lost het probleem op.


Adapter patroon


Afbeelding met dank aan http://www.uxcell.com

De adapter patroon is een structureel ontwerppatroon waarmee u een klasse opnieuw kunt gebruiken met een andere interface, zodat deze kan worden gebruikt door een systeem dat verschillende aanroepmethoden gebruikt.

Hiermee kunt u ook enkele van de ingangen die worden ontvangen van de clientklasse wijzigen, waardoor deze compatibel wordt met de functies van de adaptee.

Hoe kan ik dit gebruiken?

Een andere term om naar een adapterklasse te verwijzen is een wikkel, waarmee je in principe acties in een klasse kunt "omzetten" en deze acties in de juiste situaties opnieuw kunt gebruiken. Een klassiek voorbeeld is mogelijk wanneer u een domeinklasse maakt voor tabelklassen. In plaats van de verschillende tabelklassen op te roepen en hun functies één voor één op te roepen, kunt u al deze methoden samenvoegen in één methode met behulp van een adapterklasse. Hierdoor kunt u niet alleen de gewenste actie opnieuw gebruiken, maar voorkomt u ook dat u de code opnieuw moet schrijven als u dezelfde actie op een andere plaats moet gebruiken.

Vergelijk deze twee implementaties.

Niet-adapterbenadering

CreateOrUpdate (// inputs); $ profile = nieuw profiel (); $ profile-> CreateOrUpdate (// inputs);

Als we dit op een andere plaats opnieuw zouden moeten doen of deze code zelfs in een ander project zouden moeten hergebruiken, zouden we alles opnieuw moeten typen.

Beter

Dat is tegen het doen van zoiets als dit:

NewAccount (// inputs);

In deze situatie hebben we een wrapper-klasse, die onze accountdomeinklasse zou zijn:

CreateOrUpdate (// subset van ingangen); $ profile = nieuw profiel (); $ profile-> CreateOrUpdate (// subset of inputs); 

Op deze manier kunt u uw accountdomein opnieuw gebruiken wanneer u het nodig heeft - plus, u zou ook andere klassen onder uw domeinklasse kunnen wikkelen.


Fabrieksmethodenpatroon


Afbeelding met dank aan http://www.lankanewspappers.com

De fabrieksmethode patroon is een creatieontwerppatroon dat precies doet zoals het klinkt: het is een klasse die fungeert als een fabriek van objectinstanties.

Het belangrijkste doel van dit patroon is om de creatieprocedure die verschillende klassen kan omspannen, samen te vatten in één enkele functie. Door de juiste context aan de fabrieksmethode te geven, kan deze het juiste object retourneren.

Wanneer kan ik dit gebruiken?

De beste tijd om het patroon van de fabrieksmethode te gebruiken, is wanneer u meerdere verschillende varianten van een enkele entiteit hebt. Laten we zeggen dat je een knopklasse hebt; deze klasse heeft verschillende variaties, zoals ImageButton, InputButton en FlashButton. Afhankelijk van de plaats, moet u mogelijk verschillende knoppen maken. Hier kunt u een fabriek gebruiken om de knoppen voor u te maken!

Laten we beginnen met het maken van onze drie klassen:

_html;  class ImageButton breidt Button protected $ _html = "..." uit; // Dit moet de gewenste HTML zijn voor uw op afbeeldingen gebaseerde knop klasse InputButton breidt Button protected $ _html = "..."; // Dit moet de HTML zijn die u wilt voor uw normale knop ();  class FlashButton breidt Button protected $ _html = "..." uit; // Dit moet de HTML zijn die u wilt voor uw op Flash gebaseerde knop

Nu kunnen we onze fabrieksklasse creëren:

 

We kunnen deze code gebruiken als volgt:

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

De uitvoer moet de HTML zijn van al uw knoptypes. Op deze manier kunt u opgeven welke knop u moet maken, afhankelijk van de situatie en de voorwaarde ook opnieuw gebruiken.


Decorator patroon


Afbeelding met dank aan http://www.decoratorsdarlington.co.uk

De decorateur patroon is een structureel ontwerppatroon dat ons in staat stelt om tijdens runtime nieuw of aanvullend gedrag aan een object toe te voegen, afhankelijk van de situatie.

Het doel is om het zo te maken dat de uitgebreide functies kunnen worden toegepast op een specifiek exemplaar en tegelijkertijd nog steeds een origineel exemplaar kunnen maken dat niet over de nieuwe functies beschikt. Het maakt het ook mogelijk om meerdere decorateurs voor één exemplaar te combineren, zodat u niet voor elke instantie met één decorateur vastzit. Dit patroon is een alternatief voor subclassering, dat verwijst naar het maken van een klasse die functionaliteit van een bovenliggende klasse overneemt. In tegenstelling tot subclassing, dat het gedrag tijdens het compileren toevoegt, kunt u met "decoreren" nieuw gedrag toevoegen tijdens runtime, als de situatie daarom vraagt.

Om het decorateurpatroon te implementeren, kunnen we deze stappen volgen:

  1. Subklasse de oorspronkelijke klasse "Component" in een klasse "Decorator"
  2. Voeg in de klasse Decorator een componentaanwijzer toe als een veld
  3. Geef een component door aan de constructeur van de decorator om de componentaanwijzer te initialiseren
  4. Typ in de klasse Decorator alle "Component" -methoden om naar de "Component" -aanwijzer, en
  5. In de klasse Decorator overschrijven alle Component-methoden waarvan het gedrag moet worden gewijzigd

Stappen met dank aan http://en.wikipedia.org/wiki/Decorator_pattern

Wanneer kan ik dit gebruiken?

De beste plaats om het patroon van de decorateur te gebruiken, is wanneer u een entiteit hebt die alleen nieuw gedrag behoeft als de situatie dit vereist. Laten we zeggen dat u een HTML-linkelement hebt, een uitlogkoppeling, waarmee u iets andere dingen wilt doen op basis van de huidige pagina. Daarvoor kunnen we het decoratorpatroon gebruiken.

Laten we eerst de verschillende 'decoraties' maken die we nodig hebben.

  • Als we op de startpagina zijn en zijn aangemeld, moet deze link zijn ingepakt in h2-tags
  • Als we op een andere pagina zijn en zijn aangemeld, moet deze link zijn omsloten door onderstrepingstags
  • Als we zijn ingelogd, zorg dan dat deze link is gewikkeld in sterke tags

Zodra we onze decoraties hebben vastgesteld, kunnen we beginnen met het programmeren ervan.

_html = "Afmelden";  openbare functie setHtml ($ html) $ this -> _ html = $ html;  public function render () echo $ this -> _ html;  class LogoutLinkH2Decorator breidt HtmlLinks uit protected $ _logout_link; openbare functie __construct ($ logout_link) $ this -> _ logout_link = $ logout_link; $ This-> setHtml ("

". $ this -> _ html."

"); openbare functie __call ($ naam, $ args) $ this -> _ logout_link -> $ naam ($ args [0]); class LogoutLinkUnderlineDecorator breidt HtmlLinks uit protected $ _logout_link; public function __construct ($ logout_link) $ this -> _ logout_link = $ logout_link; $ this-> setHtml ("". $ this -> _ html.""); openbare functie __call ($ naam, $ args) $ this -> _ logout_link -> $ naam ($ args [0]); class LogoutLinkStrongDecorator breidt HtmlLinks uit protected $ _logout_link; public function __construct ($ logout_link) $ this -> _ logout_link = $ logout_link; $ this-> setHtml ("". $ this -> _ html.""); openbare functie __call ($ naam, $ args) $ this -> _ logout_link -> $ naam ($ args [0]);

We zouden het dan als volgt moeten kunnen gebruiken:

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

We kunnen hier zien hoe we meerdere decorateurs kunnen combineren als we ze nodig hebben. Omdat alle decorateurs de __call magische functie, kunnen we de methoden van de originele functie nog steeds noemen. Als we aannemen dat we momenteel op de startpagina staan ​​en zijn aangemeld, moet de HTML-uitvoer zijn:

Uitloggen


Singleton patroon


Afbeelding met dank aan http://intoxicologist.wordpress.com

De eenling ontwerppatroon is een creatieontwerppatroon dat ervoor zorgt dat u één instantie van een bepaalde klasse hebt tijdens de duur van uw runtime en een globaal toegangspunt biedt voor de afzonderlijke instantie.

Dit maakt het gemakkelijker om een ​​punt van "coördinatie" in te stellen voor andere objecten die ook de singleton-instantie gebruiken, aangezien de variabelen van de singleton altijd dezelfde zullen zijn voor alles dat dit noemt.

Wanneer kan ik dit gebruiken?

Als u een specifieke instantie van een klasse naar een andere moet doorgeven, kunt u het singleton-patroon gebruiken om te voorkomen dat u de instantie moet doorgeven via constructor of argument. Stel u voor dat u een Session-klasse hebt gemaakt, die de globale array $ _SESSION simuleert. Aangezien deze klasse maar één keer hoeft te worden geïnstantieerd, kunnen we een singleton-patroon implementeren zoals:

 

Door dit te doen, hebben we toegang tot onze sessie-instantie vanuit verschillende delen van onze code, zelfs in verschillende klassen. Deze gegevens blijven bestaan ​​gedurende alle getInstance-oproepen.


Conclusie

Er zijn veel meer ontwerppatronen om te studeren; in dit artikel heb ik alleen enkele van de meer opvallende die ik gebruik bij het programmeren, gemarkeerd. Als u geïnteresseerd bent in het lezen over de andere ontwerppatronen, heeft de ontwerppatronenpagina van Wikipedia een overvloed aan informatie. Als dat nog niet genoeg is, kun je altijd de ontwerppatronen bekijken: elementen van herbruikbare objectgeoriënteerde software, die wordt beschouwd als een van de beste ontwerppatroonboeken die beschikbaar is.

Een laatste ding: wanneer u deze ontwerppatronen gebruikt, always zorg ervoor dat je het juiste probleem probeert op te lossen. Zoals ik eerder al zei, zijn deze ontwerppatronen een dubbelzijdig zwaard: als ze in de verkeerde context worden gebruikt, kunnen ze de dingen mogelijk erger maken; maar als ze correct worden gebruikt, worden ze onmisbaar.

Als u deze tutorial nuttig vond, waarom zou u niet eens de reeks PHP-scripts op Envato Market bekijken? Er zijn duizenden handige scripts die uw ontwikkeling kunnen versnellen en u kunnen helpen betere eindresultaten te bereiken. U kunt boekingssystemen, AJAX-contactformulieren, bulletin-systemen en nog veel meer vinden. 

PHP-scripts op Envato Market