Ontwerppatronen het strategiepatroon

Tot nu toe hebben we drie ontwerppatronen in deze serie behandeld. We hebben vier categorieën van verschillende ontwerppatronen gedefinieerd. In dit artikel ga ik de Strategie ontwerppatroon, die onder valt Gedrag ontwerp patronen.

Misschien heeft u een vraag: wanneer zouden we dit ontwerppatroon moeten gebruiken? Ik zou zeggen, wanneer we verschillende manieren (algoritmen) hebben om dezelfde bewerking uit te voeren en we willen dat de applicatie de specifieke manier kiest op basis van de parameters die je hebt. Dit patroon staat ook bekend als een beleidspatroon.

Een heel eenvoudig voorbeeld voor dit artikel zou de sorteerfunctie zijn. We hebben bijvoorbeeld meerdere algoritmen voor het sorteren van arrays, maar op basis van het aantal elementen van de array moeten we kiezen welk algoritme we gebruiken dat de beste prestaties oplevert.

Dit patroon staat ook bekend als een beleidspatroon.

Het probleem

Ik zal een voorbeeld nemen van een e-commerce website met meerdere geïntegreerde betalingsgateways. Hoewel de site meerdere betalingsgateways heeft, zullen deze volgens de vereisten niet allemaal in de frontend verschijnen. In plaats daarvan moet de juiste betalingsgateway op basis van het winkelmandje worden geselecteerd.

Met een eenvoudig voorbeeld, als de waarde van de winkelwagen lager is dan $ 500, moet de betaling worden verwerkt met de PayPal-standaard, maar als deze $ 500 of meer is, moet deze worden verwerkt met behulp van opgeslagen creditcardgegevens (ervan uitgaande dat de gegevens al zijn opgeslagen) ).

Zonder een juiste strategie te implementeren, ziet onze code er als volgt uit:

In eerste instantie zullen we hoofdklassen hebben voor zowel betalen via Paypal als betalen via creditcard, die hieronder worden toegevoegd.

// Klasse om te betalen met Credit Card-klasse payByCC private $ ccNum = "; private $ ccType ="; private $ cvvNum = "; private $ ccExpMonth ="; privé $ ccExpYear = "; openbare functie betalen ($ bedrag = 0) echo" Betalen ". $ bedrag." met creditcard "; // Klasse om te betalen met PayPal-klasse payByPayPal private $ payPalEmail ="; openbare functie betalen ($ bedrag = 0) echo "Betalen". $ Bedrag. "met PayPal";  // Deze code moet elke plaats waar nodig worden herhaald. $ bedrag = 5000; if ($ amount> = 500) $ pay = new payByCC (); $ Pay> pay ($ bedrag);  else $ pay = new payByPayPal (); $ Pay> pay ($ bedrag); 

Hier zou je kunnen zeggen dat we voorwaardelijke uitspraken moeten doen om onze code te laten werken. Stel je voor hoeveel veranderingen je moet aanbrengen als we nieuwe veranderingen in die logica nodig hebben of als je een fout in die logica hebt opgelopen. We zullen een patch moeten toevoegen aan al die plaatsen waar we die code hebben gebruikt.

De oplossing

We zullen dezelfde vereiste implementeren, maar dan met behulp van het strategiepatroon, waardoor we onze code duidelijker, begrijpelijker en uitbreidbaarder kunnen maken. 

De interface

Eerst zullen we de interface implementeren die door alle verschillende betalingsgatewayklassen wordt gebruikt. Uiteindelijk zijn dit onze strategieën.

interface payStrategy openbare functie betalen ($ bedrag);  class payByCC implementeert payStrategy private $ ccNum = "; private $ ccType ="; private $ cvvNum = "; private $ ccExpMonth ="; private $ ccExpYear = "; openbare functie betalen ($ bedrag = 0) echo" Betalen ". $ bedrag." met Credit Card "; class payByPayPal implementeert payStrategy private $ payPalEmail ="; openbare functie betalen ($ bedrag = 0) echo "Betalen". $ Bedrag. "met PayPal"; 

Vervolgens zullen we onze hoofdklasse maken, die een andere strategie kan gebruiken dan we tot nu toe hebben geïmplementeerd.

class shoppingCart public $ amount = 0; openbare functie __construct ($ amount = 0) $ this-> amount = $ amount;  openbare functie getAmount () return $ this-> amount;  openbare functie setAmount ($ amount = 0) $ this-> amount = $ amount;  publieke functie payAmount () if ($ this-> amount> = 500) $ payment = new payByCC ();  else $ payment = new payByPayPal ();  $ betaling-> betalen ($ dit-> bedrag); 

Hier kunnen we zien dat onze voorwaardelijke inleg van betaalmethoden wordt gedaan in de payAmount methode. Laten we alles samenvoegen en zien hoe we dit verder kunnen gebruiken.

interface payStrategy openbare functie betalen ($ bedrag);  class payByCC implementeert payStrategy private $ ccNum = "; private $ ccType ="; private $ cvvNum = "; private $ ccExpMonth ="; private $ ccExpYear = "; openbare functie betalen ($ bedrag = 0) echo" Betalen ". $ bedrag." met Credit Card "; class payByPayPal implementeert payStrategy private $ payPalEmail ="; openbare functie betalen ($ bedrag = 0) echo "Betalen". $ Bedrag. "met PayPal";  class shoppingCart public $ amount = 0; openbare functie __construct ($ amount = 0) $ this-> amount = $ amount;  openbare functie getAmount () return $ this-> amount;  openbare functie setAmount ($ amount = 0) $ this-> amount = $ amount;  publieke functie payAmount () if ($ this-> amount> = 500) $ payment = new payByCC ();  else $ payment = new payByPayPal ();  $ betaling-> betalen ($ dit-> bedrag);  $ cart = nieuwe winkelwagen (499); $ Winkelwagen-> payAmount (); // Output 499 betalen met PayPal $ cart = nieuwe winkelwagen (501); $ Winkelwagen-> payAmount (); // Output Betaalt 501 met creditcard

We kunnen zien dat het omkeren van de betalingsgateway niet transparant is voor de toepassing. Op basis van parameters heeft het de juiste betalingsgateway beschikbaar om de transactie te verwerken.

Een nieuwe strategie toevoegen

Als in een later stadium een ​​gebruiker een nieuwe strategie moest toevoegen (nieuwe betalingsgateway hier) met een andere logica, zou het in dit geval heel eenvoudig zijn. Laten we zeggen dat we een nieuwe betalingsgateway, moneybooker, willen toevoegen en geld willen verwerken wanneer het winkelwagentje groter is dan $ 500 maar minder dan $ 1.000.

Alles wat we moeten doen is een nieuwe strategieklasse maken die onze interface implementeert en we zijn goed om te gaan.

klasse payByMB implementeert payStrategy private $ mbEmail = "; public function pay ($ amount = 0) echo" Paying ". $ amount." using Money Booker ";

We hebben onze nieuwe strategieklasse nu klaar en wat we moeten veranderen, is ons belangrijkste payAmount methode. Het moet worden gewijzigd zoals hieronder:

publieke functie payAmount () if ($ this-> amount> 500 && $ this-> amount < 1000)  $payment = new payByMB();  else if($this->aantal> = 500) $ payment = new payByCC ();  else $ payment = new payByPayPal ();  $ betaling-> betalen ($ dit-> bedrag); 

Hier kunt u zien dat we wijzigingen hebben aangebracht in onze payAmount methode alleen, in plaats van in de clientcode van waaruit deze methode wordt aangeroepen.

Conclusie

Vandaar dat, als we verschillende manieren hebben om dezelfde taak uit te voeren (in softwaretaal als we meerdere algoritmen hebben om dezelfde bewerking uit te voeren), we zouden moeten overwegen om het Strategiepatroon te implementeren.. 

Door dit patroon te gebruiken, kunnen we een algoritme toevoegen / verwijderen omdat het overschakelen van deze algoritmen niet transparant is voor de toepassing. 

Ik heb mijn best gedaan om een ​​elementair en toch handig voorbeeld te geven om het patroon van het strategieontwerp te demonstreren, maar als u aanvullende opmerkingen of vragen heeft, aarzel dan niet om deze in de onderstaande feed toe te voegen.