原文地址
最近写了一个集成各家支付的开源项目(支付宝与微信)。项目地址。让调用支付变得更加简单、统一。目前已经在公司商城推行使用,上海一米市集也采用了这个支付集成项目。
我可不是打广告哦,只是为了让大家可以有一个只管的了解渠道。可以去看看。
今天主要聊的不是支付,而是说说其中使用的一个设计模式:策略模式。
策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
这是书本上给的定义,是不是完全搞不懂?我结合支付,再来给你解释一下,一定就赫然开朗啦!
首先是这句 让算法独立于使用它的客户而变化 (我是倒着在分析哦)。
这是什么意思?也就是说实现一个功能,有多个方法,而选择这个方法的控制权不要交给客户端,也就说了,我换了实现方法,客户端是不需要改代码的。
那么要做到这样子,必然提供给客户端的一个稳定的调用类(称为环境类),首先调用这个类能够产生一个具体算法的实例,其次这个调用类,还需要公布一个接口,让客户端调用实现具体功能。
那么做到以上,无论实现多少种双方,客户端的调用都是不变的。控制权都在这个调用类里边,由它来决定到底采用哪种算法。
下面来接着说算法部分。如果需要 环境类 提供一个实现具体功能的接口,那么这些算法必然实现了一个公共接口(称为抽象策略类)。才能确保有相同的方法提供出来。然后具体的算法都要实现这个接口。这也就是上面定义中的 将每一个算法封装起来 每一个具体的算法称为:具体策略类
不知道这个解释大家清楚定义了没有,如果还不清楚,看类图
策略模式包含的角色如下:
这下子是不是很清楚了?策略模式是使用非常广泛的一个设计模式。他很好的提现了:控制反转、依赖注入等思想。有同学说,不想看文字,有本事上代码呀!嗯,我喜欢,新鲜出炉的代码来了
在整个模式中,Strategy 起着承上启下的作用。我就先来实现它
interface ChargeStrategy
{
public function charge();
}
OK,抽象策略类就完成了,他的主要目的就是规范一个必须要实现的方法,环境类依赖这个接口进行编程。
下面接着写算法的实现。还是以支付宝支付、微信支付为例。对于用户来说他要实现的功能是支付。那么支付又有多种选择(多种算法)。但是客户端不需要做出选择,他把这个权利让 环境类 去选择。这样子客户端就简单了。所有的算法需要实现 策略类接口。
// 支付宝策略类
class AliCharge implements ChargeStrategy
{
public function charge()
{
// 完成支付宝的相关逻辑
}
}
// 微信策略类
class WxCharge implements ChargeStrategy
{
public function charge()
{
// 完成微信的相关逻辑
}
}
这里声明一下,这里为了纯粹的把 策略模式 讲明白,抛开了很多细枝末节,真正的支付中的实现,大家可以去看看项目的源代码。
final class ChargeContext
{
/**
* @var ChargeStrategy $charge
*/
private $charge;
public function initInstance($channel)
{
if ($channel == 'ali') {
$this->charge = new AliCharge;
} elseif ($chananel == 'wx') {
$this->charge = new WxCharge;
} else {
$this->charge = null;
}
}
public function charge()
{
if (is_null($this->charge)) {
exit('初始化错误');
}
$this->charge->charge();
}
}
以上就基本完成了,而对于客户端来说,就非常简单啦。
// 获取用户选择的支付方式
$channel = trim($_GET['channel']);
$context = new ChargeContext();
// 初始化支付实例
$context->initInstance($channel);
// 调用功能
$context->charge();
代码写完了,不知道大家有没有感受到好处,这个模式很好的实现了开闭原则。比如说:现在新增加了一个PayPal支付方式。那么只需要添加一个PayPal的策略算法。在ChargeContext中把对应的实例初始化加进去,其他地方都不需要动的。
最后再说几句,不知道大家注意到没有,在 ChargeContext
这个类中,其实还使用了 简单工厂 这个模式。这里想给大家说明的是,其实设计模式只是一些编码的技巧,完全可以自由搭配组合,基本思想就是 设计模式的六大原则
当然,实际编码中也没有必要非要都实现这六大原则。这个也没有什么规范,只能大家多去实践,然后自己约定出一套适合业务的规范就好。