So far, we have covered three design patterns in this series. We define four different categories of design patterns. In this article, I will explain theStrategic Design Pattern, which falls under theBehavioral Design Patterns.
You may have a question: When should you use this design pattern? I would say when we have multiple methods (algorithms) to perform the same operation and we want the application to choose a specific method based on the parameters you have. This mode is also called strategy mode.
A very simple example for this article is the sorting function. For example, we have multiple algorithms for sorting arrays, but depending on the number of array elements, we should choose which algorithm to use to get the best performance.
This mode is also called strategy mode.
I will give an example of an e-commerce website that integrates multiple payment gateways. Although the website has multiple payment gateways, upon request, they are not all displayed on the front-end. Instead, the appropriate payment gateway needs to be selected on the fly based on the cart amount.
As a simple example, if the cart value is less than $500, the payment should be processed using PayPal standards, but if the amount is $500 or more, it should be processed using the stored credit card details (assuming the details have been storage).
Without the correct strategy implemented, our code would look like this:
First we will provide the main classes for payment via Paypal and payment via credit card, which will be added below.
// Class to pay using Credit Card class payByCC { private $ccNum = ''; private $ccType = ''; private $cvvNum = ''; private $ccExpMonth = ''; private $ccExpYear = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using Credit Card"; } } // Class to pay using PayPal class payByPayPal { private $payPalEmail = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using PayPal"; } } // This code needs to be repeated every place where ever needed. $amount = 5000; if($amount >= 500) { $pay = new payByCC(); $pay->pay($amount); } else { $pay = new payByPayPal(); $pay->pay($amount); }
Here, you might say that we need to put conditional statements to make our code work properly. Imagine how many changes you need to make when we need to make new changes to this logic or you find a bug in this logic. We have to add patches to all places where this code is used.
We will implement the same requirement, but using the Strategy pattern, which allows us to make our code clearer, easier to understand and extensible.
First, we will implement the interfaces that all the different payment gateway classes will use. Ultimately, these are our strategies.
interface payStrategy { public function pay($amount); } class payByCC implements payStrategy { private $ccNum = ''; private $ccType = ''; private $cvvNum = ''; private $ccExpMonth = ''; private $ccExpYear = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using Credit Card"; } } class payByPayPal implements payStrategy { private $payPalEmail = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using PayPal"; } }
Next we will create our main class, which can use different strategies than the ones we have implemented so far.
class shoppingCart { public $amount = 0; public function __construct($amount = 0) { $this->amount = $amount; } public function getAmount() { return $this->amount; } public function setAmount($amount = 0) { $this->amount = $amount; } public function payAmount() { if($this->amount >= 500) { $payment = new payByCC(); } else { $payment = new payByPayPal(); } $payment->pay($this->amount); } }
Here we can see that the conditional loading of our payment method is done in thepayAmount
method. Let's wrap everything together and see how to use it further.
interface payStrategy { public function pay($amount); } class payByCC implements payStrategy { private $ccNum = ''; private $ccType = ''; private $cvvNum = ''; private $ccExpMonth = ''; private $ccExpYear = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using Credit Card"; } } class payByPayPal implements payStrategy { private $payPalEmail = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using PayPal"; } } class shoppingCart { public $amount = 0; public function __construct($amount = 0) { $this->amount = $amount; } public function getAmount() { return $this->amount; } public function setAmount($amount = 0) { $this->amount = $amount; } public function payAmount() { if($this->amount >= 500) { $payment = new payByCC(); } else { $payment = new payByPayPal(); } $payment->pay($this->amount); } } $cart = new shoppingCart(499); $cart->payAmount(); // Output Paying 499 using PayPal $cart = new shoppingCart(501); $cart->payAmount(); //Output Paying 501 using Credit Card
We can see that the payment gateway rollover is not transparent to the application. Depending on the parameters, it has the appropriate payment gateway available to process the transaction.
If at a later stage the user needs to add a new strategy with different logic (here a new payment gateway), it will be very simple in this case. Let’s say we want to add a new payment gateway, Moneybooker, and want to process funds when the cart amount exceeds $500 but falls below $1,000.
All we need to do is create a new strategy class that implements our interface and we are good to go.
class payByMB implements payStrategy { private $mbEmail = ''; public function pay($amount = 0) { echo "Paying ". $amount. " using Money Booker"; } }
We now have our new strategy class ready, all we need to change is the mainpayAmount
method. Need to be modified as follows:
public function payAmount() { if($this->amount > 500 && $this->amount < 1000) { $payment = new payByMB(); } else if($this->amount >= 500) { $payment = new payByCC(); } else { $payment = new payByPayPal(); } $payment->pay($this->amount); }
Here you can see that we only made the change in thepayAmount
method, not in the client code that calls the method.
So to conclude, when we have multiple ways to perform the same task (in software languages, when we have multiple algorithms to perform the same operation), we should consider implementing the Strategy pattern.
By using this mode, we can add/remove algorithms freely since the switching of these algorithms is not transparent to the application.
I've tried my best to provide a basic but useful example to demonstrate the Strategy Design Pattern, but if you have additional comments or questions, please feel free to add them to the feed below.
The above is the detailed content of Strategy pattern: one of the design patterns. For more information, please follow other related articles on the PHP Chinese website!