到目前为止,我们已经介绍了本系列中的三种设计模式。我们定义了四类不同的设计模式。在本文中,我将解释策略设计模式,它属于行为设计模式。
你可能有一个问题:什么时候应该使用这种设计模式?我想说,当我们有多种方法(算法)来执行相同的操作,并且我们希望应用程序根据您拥有的参数选择特定的方法时。这种模式也称为策略模式。
本文的一个非常简单的示例是排序功能。例如,我们有多种对数组进行排序的算法,但是根据数组元素的数量,我们应该选择使用哪种算法来获得最佳性能。
此模式也称为策略模式。
问题
我将举一个集成了多个支付网关的电子商务网站的例子。尽管该网站有多个支付网关,但根据要求,它们不会全部显示在前端。相反,需要根据购物车金额即时选择适当的支付网关。
举个简单的例子,如果购物车价值低于 500 美元,则应使用 PayPal 标准处理付款,但如果金额为 500 美元或以上,则应使用存储的信用卡详细信息进行处理(假设详细信息已存储)。
如果没有实施正确的策略,我们的代码将如下所示:
首先,我们将提供通过 Paypal 支付和通过信用卡支付的主要类,这些类将在下面添加。
// 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);
}
登录后复制
在这里,您可能会说我们需要放置条件语句才能使我们的代码正常工作。想象一下,当我们需要对该逻辑进行新的更改或者您发现该逻辑中的错误时,您需要进行多少更改。我们必须向所有使用该代码的地方添加补丁。
解决方案
我们将实现相同的要求,但使用策略模式,这使我们能够使我们的代码更加清晰、易于理解和可扩展。
界面
首先,我们将实现所有不同支付网关类将使用的接口。最终,这些是我们的策略。
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);
}
}
登录后复制
在这里我们可以看到我们的付款方式的条件加载是在 payAmount
方法中完成的。让我们将所有内容包装在一起,看看如何进一步使用它。
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
登录后复制
我们可以看到支付网关的翻转对于应用程序来说并不透明。根据参数,它有适当的支付网关可用于处理交易。
添加新策略
如果在后期用户需要添加具有不同逻辑的新策略(此处为新支付网关),在这种情况下会非常简单。假设我们要添加一个新的支付网关 Moneybooker,并希望在购物车金额超过 500 美元但低于 1,000 美元时处理资金。
我们需要做的就是创建一个新的策略类来实现我们的接口,我们就可以开始了。
class payByMB implements payStrategy {
private $mbEmail = '';
public function pay($amount = 0) {
echo "Paying ". $amount. " using Money Booker";
}
}
登录后复制
我们现在已经准备好了新的策略类,我们需要更改的是主要的 payAmount
方法。需要修改如下:
public function payAmount() {
if($this->amount > 500 && $this->amount amount >= 500) {
$payment = new payByCC();
} else {
$payment = new payByPayPal();
}
$payment->pay($this->amount);
}
登录后复制
在这里您可以看到我们仅在 payAmount
方法中进行了更改,而不是在调用该方法的客户端代码中进行了更改。
结论
因此得出结论,当我们有多种方法来执行同一任务时(在软件语言中,当我们有多种算法来执行同一操作时),我们应该考虑实现策略模式。
通过使用这种模式,我们可以自由地添加/删除算法,因为这些算法的切换对于应用程序来说并不透明。
我已尽力提供一个基本但有用的示例来演示策略设计模式,但如果您有其他意见或问题,请随时将它们添加到下面的提要中。
以上就是策略模式:设计模式中的一种的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!