策略模式

需求:银行收银系统,营业员根据客户所购买商品的单价和数量,向客户收费。其中有几种模式:原价模式、打折模式、满减模式,每一种商品在结账的时候都要选择一种模式进行对应,且模式中的值有不同。

根据需求,准备以下不同的类。

 

一、抽象策略接口

interface Strategy
{
    public function getResult();
}

 

二、原价策略类

class Cash implements Strategy
{
    protected $price;
    protected $amount;

    public function __construct($price,$amount)
    {
        $this->price = $price;
        $this->amount = $amount;
    }

    public function getResult()
    {
        return $this->price * $this->amount;
    }
}

 

三、打折策略类

class Discount implements Strategy
{
    protected $price;
    protected $amount;
    protected $rate;

    public function __construct($price,$amount,$rate)
    {
        $this->price = $price;
        $this->amount = $amount;
        $this->rate = $rate;
    }

    public function getResult()
    {
        return $this->price * $this->amount * $this->rate;
    }
}

 

四、满减策略类

class Rebate implements Strategy
{
    protected $price;
    protected $amount;
    protected $rule;

    public function __construct($price,$amount,$rule)
    {
        $this->price = $price;
        $this->amount = $amount;
        $this->rule = $rule;
    }

    public function getResult()
    {
        $money = $this->price * $this->amount;
        $result = self::_minusMoney($money,$this->rule);

        return $result;
    }

    /**
     * 计算满减后的金额
     * @param $money
     * @param $rule
     * @return mixed
     */
    private function _minusMoney($money,$rule)
    {
        $result = $money - floor($money/$rule[0]) * $rule[1];
        return $result;
    }
}

 

五、上下文类

class Context
{
    private $strategy;
    public function __construct(Strategy $strategy)
    {
        $this->strategy = $strategy;
    }

    public function countResult()
    {
        return $this->strategy->getResult();
    }
}

 

六、简单工厂类

class Factory
{
    public static function createObj($params)
    {
        $obj = null;

        $price = $params['price'];
        $amount = $params['amount'];
        $discount = isset($params['discount'])?$params['discount']:1;
        $rule = isset($params['rule'])?$params['rule']:[];

        switch($params['type'])
        {
            case 1:
                $obj = new Cash($price,$amount);
                break;
            case 2:
                $obj = new Discount($price,$amount,$discount);
                break;
            case 3:
                $obj = new Rebate($price,$amount,$rule);
                break;
        }

        return $obj;
    }
}

 

七、测试代码如下:

$result = 0;

$params = [
    'type'=>1,
    'price'=>12,
    'amount'=>5
];
$strategy_cash = new Context(Factory::createObj($params));
echo '原价商品,费用为:',$strategy_cash->countResult();
$result += $strategy_cash->countResult();

$params = [
    'type'=>2,
    'price'=>12,
    'amount'=>5,
    'discount'=>0.8
];
$strategy_discount = new Context(Factory::createObj($params));
echo '打折商品,费用为:',$strategy_discount->countResult();
$result += $strategy_cash->countResult();

$params = [
    'type'=>3,
    'price'=>120,
    'amount'=>5,
    'rule'=>[300,40]
];
$strategy_rebate = new Context(Factory::createObj($params));
echo '满减商品,费用为:',$strategy_rebate->countResult();

$result += $strategy_cash->countResult();
echo '总费用为:',$result;

 

八、UML图如下:

 

总结:

1. 策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。

2. 当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句。

3. 策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

posted @ 2018-06-26 20:41  宫丫  阅读(154)  评论(0编辑  收藏  举报