Design Patterns Le modèle de stratégie

Jusqu'à présent, nous avons couvert trois modèles de conception de cette série. Nous avons défini quatre catégories de modèles de conception différents. Dans cet article, je vais expliquer la Modèle de conception de stratégie, qui tombe sous Modèles de conception comportementale.

Vous pourriez avoir une question: quand devrions-nous utiliser ce modèle de conception? Je dirais que, lorsque nous avons plusieurs façons (algorithmes) d’effectuer la même opération et que nous voulons que l’application choisisse la manière spécifique en fonction des paramètres que vous avez. Ce modèle est également appelé modèle de stratégie..

Un exemple très simple pour cet article serait la fonctionnalité de tri. Par exemple, nous avons plusieurs algorithmes pour trier les tableaux, mais en fonction du nombre d'éléments du tableau, nous devons choisir l'algorithme à utiliser qui offre les meilleures performances..

Ce modèle est également appelé modèle de stratégie..

Le problème

Je vais prendre un exemple de site Web de commerce électronique comportant plusieurs passerelles de paiement intégrées. Bien que le site dispose de plusieurs passerelles de paiement, conformément aux exigences, elles ne s'afficheront pas toutes au début. Au lieu de cela, la passerelle de paiement appropriée doit être sélectionnée à la volée en fonction du montant du panier..

À l'aide d'un exemple simple, si le panier est inférieur à 500 USD, le paiement doit être traité selon la norme PayPal. S'il est égal à 500 USD ou plus, il doit être traité à l'aide des informations de carte de crédit stockées (en supposant que ces informations sont déjà stockées.) ).

Sans mettre en œuvre une stratégie appropriée, notre code ressemblerait à ceci:

Au début, nous aurons des classes principales pour payer à la fois via Paypal et par carte de crédit, qui sont ajoutées ci-dessous.

// Classe à payer avec la classe Carte de crédit payByCC private $ ccNum = "; private $ ccType ="; private $ cvvNum = "; private $ ccExpMonth ="; private $ ccExpYear = "; fonction publique paye ($ amount = 0) echo" Payant ". montant $." utilisant une carte de crédit "; // Classe à payer avec la classe PayPal payByPayPal private $ payPalEmail ="; fonction publique paye ($ montant = 0) echo "Paying". $ montant. "utiliser PayPal";  // Ce code doit être répété chaque fois que nécessaire. $ montant = 5000; if ($ amount> = 500) $ pay = new payByCC (); $ pay-> pay (montant);  else $ pay = new payByPayPal (); $ pay-> pay (montant); 

Ici, vous pourriez dire que nous devons placer des instructions conditionnelles pour que notre code fonctionne. Imaginez le nombre de modifications que vous devez effectuer lorsque nous demandons de nouvelles modifications dans cette logique ou si vous avez détecté un bogue dans cette logique. Nous devrons ajouter un patch à tous les endroits où nous avons utilisé ce code.

La solution

Nous allons mettre en œuvre la même exigence, mais en utilisant le modèle de stratégie, ce qui nous permet de rendre notre code plus clair, compréhensible et extensible.. 

L'interface

Tout d'abord, nous allons implémenter l'interface qui sera utilisée par toutes les classes de passerelles de paiement. En fin de compte, ce sont nos stratégies.

interface payStrategy fonction publique paye (montant en $);  class payByCC implémente payStrategy private $ ccNum = "; private $ ccType ="; private $ cvvNum = "; private $ ccExpMonth ="; private $ ccExpYear = "; fonction publique paye ($ montant = 0) echo" Payant ". montant $." utilisant une carte de crédit "; classe payByPayPal implémente payStrategy privé $ payPalEmail ="; fonction publique paye ($ montant = 0) echo "Paying". $ montant. "utiliser PayPal"; 

Ensuite, nous allons créer notre classe principale, qui peut utiliser une stratégie différente de celle que nous avons mise en place jusqu'à présent..

classe shoppingCart montant public $ = 0; fonction publique __construct ($ montant = 0) $ ceci-> montant = $ montant;  fonction publique getAmount () return $ this-> montant;  fonction publique setAmount ($ montant = 0) $ ceci-> montant = $ montant;  fonction publique payAmount () if ($ this-> montant> = 500) $ payment = new payByCC ();  else $ payment = new payByPayPal ();  $ paiement-> payer ($ ceci-> montant); 

Nous pouvons voir ici que notre chargement conditionnel des méthodes de paiement se fait dans le montant du paiement méthode. Enveloppons le tout ensemble et voyons comment nous pouvons utiliser cela davantage.

interface payStrategy fonction publique paye (montant en $);  class payByCC implémente payStrategy private $ ccNum = "; private $ ccType ="; private $ cvvNum = "; private $ ccExpMonth ="; private $ ccExpYear = "; fonction publique paye ($ montant = 0) echo" Payant ". montant $." utilisant une carte de crédit "; classe payByPayPal implémente payStrategy privé $ payPalEmail ="; fonction publique paye ($ montant = 0) echo "Paying". $ montant. "utiliser PayPal";  class shoppingCart public $ amount = 0; fonction publique __construct ($ montant = 0) $ ceci-> montant = $ montant;  fonction publique getAmount () return $ this-> montant;  fonction publique setAmount ($ montant = 0) $ ceci-> montant = $ montant;  fonction publique payAmount () if ($ this-> montant> = 500) $ payment = new payByCC ();  else $ payment = new payByPayPal ();  $ paiement-> payer ($ ceci-> montant);  $ cart = new shoppingCart (499); $ cart-> payAmount (); // Sortie payante 499 avec PayPal $ cart = new shoppingCart (501); $ cart-> payAmount (); // Sortie payante 501 avec une carte de crédit

Nous pouvons voir que le basculement de la passerelle de paiement n’est pas transparent pour l’application. Sur la base de paramètres, il dispose de la passerelle de paiement appropriée pour traiter la transaction..

Ajout d'une nouvelle stratégie

Si, ultérieurement, un utilisateur devait ajouter une nouvelle stratégie (nouvelle passerelle de paiement ici) avec une logique différente, ce serait très simple dans ce cas. Supposons que nous voulions ajouter une nouvelle passerelle de paiement, moneybooker, et traiter de l'argent lorsque le montant du panier est supérieur à 500 USD mais inférieur à 1 000 USD..

Tout ce que nous avons à faire est de créer une nouvelle classe de stratégie qui implémente notre interface et nous sommes prêts à partir..

La classe payByMB implémente payStrategy private $ mbEmail = "; fonction publique pay ($ amount = 0) echo" Paying ". $ amount." using Money Booker ";

Nous avons notre nouvelle classe de stratégie prête maintenant, et ce que nous devons changer est notre principale montant du paiement méthode. Il doit être changé comme ci-dessous:

fonction publique payAmount () if ($ this-> montant> 500 && $ this-> montant < 1000)  $payment = new payByMB();  else if($this->montant> = 500) $ payment = new payByCC ();  else $ payment = new payByPayPal ();  $ paiement-> payer ($ ceci-> montant); 

Ici, vous pouvez voir que nous avons apporté des modifications à notre montant du paiement méthode uniquement, au lieu du code client à partir duquel cette méthode appelle.

Conclusion

Par conséquent, pour conclure, lorsque nous avons plusieurs façons d’exécuter la même tâche (en langage logiciel, lorsque nous avons plusieurs algorithmes pour effectuer la même opération), nous devrions envisager de mettre en œuvre le modèle Strategy.. 

En utilisant ce modèle, nous sommes libres d'ajouter / de supprimer un algorithme car la commutation de ces algorithmes n'est pas transparente pour l'application.. 

J'ai essayé de mon mieux pour fournir un exemple élémentaire et utile pour illustrer le modèle de conception de la stratégie, mais si vous avez des commentaires ou des questions supplémentaires, n'hésitez pas à les ajouter dans le fil ci-dessous..