5. php设计模式:策略模式的实际应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hel12he/article/details/52003433

原文地址

最近写了一个集成各家支付的开源项目(支付宝与微信)。项目地址。让调用支付变得更加简单、统一。目前已经在公司商城推行使用,上海一米市集也采用了这个支付集成项目。

我可不是打广告哦,只是为了让大家可以有一个只管的了解渠道。可以去看看。

今天主要聊的不是支付,而是说说其中使用的一个设计模式:策略模式。

策略模式的定义解析

策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

这是书本上给的定义,是不是完全搞不懂?我结合支付,再来给你解释一下,一定就赫然开朗啦!

首先是这句 让算法独立于使用它的客户而变化 (我是倒着在分析哦)。
这是什么意思?也就是说实现一个功能,有多个方法,而选择这个方法的控制权不要交给客户端,也就说了,我换了实现方法,客户端是不需要改代码的。

那么要做到这样子,必然提供给客户端的一个稳定的调用类(称为环境类),首先调用这个类能够产生一个具体算法的实例,其次这个调用类,还需要公布一个接口,让客户端调用实现具体功能。

那么做到以上,无论实现多少种双方,客户端的调用都是不变的。控制权都在这个调用类里边,由它来决定到底采用哪种算法。

下面来接着说算法部分。如果需要 环境类 提供一个实现具体功能的接口,那么这些算法必然实现了一个公共接口(称为抽象策略类)。才能确保有相同的方法提供出来。然后具体的算法都要实现这个接口。这也就是上面定义中的 将每一个算法封装起来 每一个具体的算法称为:具体策略类

不知道这个解释大家清楚定义了没有,如果还不清楚,看类图

类图演示

策略模式包含的角色如下:

  • Context: 环境类
  • Strategy: 抽象策略类
  • ConcreteStrategy: 具体策略类

image

这下子是不是很清楚了?策略模式是使用非常广泛的一个设计模式。他很好的提现了:控制反转、依赖注入等思想。有同学说,不想看文字,有本事上代码呀!嗯,我喜欢,新鲜出炉的代码来了

策略模式PHP代码实现

在整个模式中,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 这个类中,其实还使用了 简单工厂 这个模式。这里想给大家说明的是,其实设计模式只是一些编码的技巧,完全可以自由搭配组合,基本思想就是 设计模式的六大原则

当然,实际编码中也没有必要非要都实现这六大原则。这个也没有什么规范,只能大家多去实践,然后自己约定出一套适合业务的规范就好。

阅读更多

没有更多推荐了,返回首页