PHP7下的策略模式实践

实践背景

由于公司业务变更,需要对会员系统做一些功能上的新增,考虑到之前的会员系统升级方面的业务考虑不周全导致代码逻辑也不完善,因此需要把之前与会员系统相关的代码推到重来,考虑到这种业务场景和之前学习过的策略模式比较相像,决定进行一番实践。

业务说明

1 会员等级:普通会员、黄金会员、白金会员、钻石会员、蓝钻会员
2 升级限制:每一级会员升级到下一级会员或者跨级都会有响应的条件限制

实现细节

  1. 首先会员的升级策略不同,以后也会有比较大的变化,但是可以抽象出两个行为——会员是否具有升级条件、升级逻辑,所以可以抽象出一个接口
namespace app\api\service\vip;

interface IVipUpStrategyBase
{
    public function up();

    public function checkLevel();
}
  1. 有了接口就应该有实现类了,但是考虑到会有公用逻辑,中间加一层Base类用来承载一些实例属性
namespace app\api\service\vip;

/**
 * @property VipUpParams $vipUpParams
 */
class VipUpStrategyBase implements IVipUpStrategyBase
{
    protected $vipUpParams = null;

    /**
     * @var bool 是否有参拍批次
     */
    protected $isHaveSession = false;

    public function checkLevel()
    {
    	// 这里是检查能否升级的方法
        return true;
    }

    public function up()
    {
		// 这里是实际执行升级逻辑的方法
    }
	
	// VipUpParams 是接收外部传递给实例参数的类
    public function setVipUpParams(VipUpParams $params)
    {
        $this->vipUpParams = $params;
    }
}

给出一个我的VipUpParams 示例

class VipUpParams
{
    // 用户原等级
    protected $originLevel;

    // 用户期望升级到的等级
    protected $upLevel;

    protected $userInfo;


    /**
     * @return mixed
     */
    public function getOriginLevel()
    {
        return $this->originLevel;
    }

    /**
     * @param mixed $originLevel
     */
    public function setOriginLevel($originLevel)
    {
        $this->originLevel = $originLevel;
    }

    /**
     * @return mixed
     */
    public function getUpLevel()
    {
        return $this->upLevel;
    }

    /**
     * @param mixed $upLevel
     */
    public function setUpLevel($upLevel)
    {
        $this->upLevel = $upLevel;
    }

    /**
     * @return mixed
     */
    public function getUserInfo()
    {
        return $this->userInfo;
    }

    /**
     * @param mixed $userInfo
     */
    public function setUserInfo($userInfo)
    {
        $this->userInfo = $userInfo;
    }
}
  1. 接下来就是策略类了
namespace app\api\service\vip\strategyImpl;
class RegularToPlatinum extends VipUpStrategyBase
{
    public function up()
    {
        $this->checkLevel();
    }
}

可以有N多种策略

namespace app\api\service\vip\strategyImpl;
class RegularToGold extends VipUpStrategyBase
{
    public function up()
    {
        $this->checkLevel();
    }
}
namespace app\api\service\vip\strategyImpl;
class RegularToDiamond extends VipUpStrategyBase
{
    public function up()
    {
        $this->checkLevel();
    }
}

等等

  1. 有了多个策略类,接下来就需要根据用户输入调度策略类,由于我这里的用户输入只有两个——原级别、升级后级别,所以我做了一个Map的类
namespace app\api\service\vip;
use app\api\service\vip\enum\VipUpStrategyEnum;

class VipUpStrategyMap
{
    protected static $map = [
        VipUpStrategyEnum::RegularToPlatinum => 'app\\api\\service\\vip\\strategyImpl\\RegularToPlatinum',
    ];

    public static function getMap() {
        return self::$map;
    }
}
namespace app\api\service\vip\enum;
class VipUpStrategyEnum
{
    /**
     * 普通会员升级
     */
    // 普通会员升级为黄金会员
    const RegularToGold = '1-2';

    // 普通会员升级为白金会员
    const RegularToPlatinum = '1-3';

    // 普通会员升级到钻石会员
    const RegularToDiamond = '1-4';

    // 通会员升级到蓝钻会员
    const RegularToBlueDiamond = '1-5';


    /**
     * 黄金会员升级升级
     */
    // 黄金会员升级为白金会员
    const GoldToPlatinum = '2-3';

    // 黄金会员升级到钻石会员
    const GoldToDiamond = '2-4';

    // 黄金会员会员升级到蓝钻会员
    const GoldToBlueDiamond = '1-5';


    /**
     * 白金会员升级升级
     */
    // 白金会员升级到钻石会员
    const PlatinumToDiamond = '3-4';

    // 白金会员会员升级到蓝钻会员
    const PlatinumToBlueDiamond = '3-5';

    /**
     * 钻石会员升级升级
     */
    // 钻石会员会员升级到蓝钻会员
    const DiamondToBlueDiamond = '3-5';
}

当然还有最重要的调度类dispatcher 采用反射实现调度

namespace app\api\service\vip;
use app\api\service\vip\exceptions\StrategyNotFound;

class VipUpDispatcher
{
    protected $vipUpParams = null;

    public function __construct(VipUpParams $vipUpParams)
    {
        $this->vipUpParams = $vipUpParams;
    }

    public function dispatch() {
        $levelStrategy = $this->vipUpParams->getOriginLevel().'-'.$this->vipUpParams->getUpLevel();
        $map = VipUpStrategyMap::getMap();
        if(!isset($map[$levelStrategy]) || empty($map[$levelStrategy])) {
            throw new StrategyNotFound();
        }
        $strategyClass = new \ReflectionClass($map[$levelStrategy]);
        $strategyInstance = $strategyClass->newInstance();
        $strategyInstance->setVipUpParams($this->vipUpParams);
        return $strategyInstance->up();
    }
}
  1. 最后的最后客户端调用
namespace app\api\service\vip;
use app\api\service\vip\exceptions\StrategyNotFound;
class Test extends \PHPUnit_Framework_TestCase{
	public function testMain() {
        $userInfo = \think\Db::name("user")->where('id', '311')->find();
        $originLevel = $userInfo['level'];
        $upLevel = 13;
        $vipUpParams = new VipUpParams();
        $vipUpParams->setOriginLevel($originLevel);
        $vipUpParams->setUpLevel($upLevel);
        $vipUpParams->setUserInfo($userInfo);
        $vipUpDispatcher = new VipUpDispatcher($vipUpParams);
        try {
            $res = $vipUpDispatcher->dispatch();
        } catch (StrategyNotFound $e) {
            $this->error($e->getMessage(), null, $e->getCode());
        }
        $this->success('', $res);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值