由于公司业务变更,需要对会员系统做一些功能上的新增,考虑到之前的会员系统升级方面的业务考虑不周全导致代码逻辑也不完善,因此需要把之前与会员系统相关的代码推到重来,考虑到这种业务场景和之前学习过的策略模式比较相像,决定进行一番实践。
1 会员等级:普通会员、黄金会员、白金会员、钻石会员、蓝钻会员
2 升级限制:每一级会员升级到下一级会员或者跨级都会有响应的条件限制
namespace app\api\service\vip;
interface IVipUpStrategyBase
{
public function up();
public function checkLevel();
}
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;
}
}
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();
}
}
等等
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();
}
}
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);
}
}