《大话设计模式》之策略模式

KarlXu 2021-03-02 14:22:16原创浏览量110

策略模式

> 将算法分别封装起来,让它们可以相互替换,此模式让算法的变化不会影响到其调用者


实现一个简单的收银功能

class Program
{
   
   public function calculate($price, $num)
   {
      // 实际项目中要考虑浮点计算时精度丢失的问题
      $totalPrice = $price * $num;
      echo '单价'. $price .',数量'. $num .',总价:'. $totalPrice ."\n";
      return $totalPrice;
   }

}

$total = 0;

$program = new Program();

$total += $program->calculate(5, 2);

$total += $program->calculate(12, 3);

echo '总计:'. $total;


/**

输出结果:

单价5,数量2,总价:10
单价12,数量3,总价:36
总计:46

**/

看起来已经满足需求,但是如果功能继续扩展,需要对某些商品进行打折

class Program
{

public function calculate($price, $num, $discount = 0)
{
$proportion = 1;
switch ($discount) {
case 8:
echo '享受8,';
$proportion = 0.8;
break;

case 5:
echo '享受5,';
$proportion = 0.5;
break;

default:
# code...
break;
}
$totalPrice = $price * $num * $proportion;
echo '单价'. $price .',数量'. $num .',总价:'. $totalPrice ."\n";
return $totalPrice;
}

}

$total = 0;

$program = new Program();

$total += $program->calculate(5, 2);

$total += $program->calculate(12, 3, 8);

$total += $program->calculate(12, 3, 5);

echo '总计:'. $total;

/**

输出结果:

单价5,数量2,总价:10
享受8,单价12,数量3,总价:28.8
享受5,单价12,数量3,总价:18
总计:56.8

**/

假如需要更多的折扣、满减、购买赠送积分,那么这里明显不能这么编写,总不可能一个折扣就新增一个 case

单纯使用工厂模式并不能解决问题,应当使用策略模式,把相同的算法归纳在一个策略里

例如不管打几折,都算是一种策略,满减和普通支付是另外的策略

建立一个抽象类 CashSuper 类,约束继承的子类(每个策略)都实现自己的计算方式 acceptCach

建立一个 CashContext 类,用来维护引用的对象,CashContext 类的构造方法传递进来的是抽象类 CashSuper 类型

而不是某个子类类型,而我们的子类都实现了计算方法,只需要传不同的子类就可以实现不同的策略


// 抽象类
abstract class CashSuper
{
// 约束子类实现计算方法
abstract function acceptCach($price, $num);
}

// 正常支付策略
class CashNormal extends CashSuper
{
public function acceptCach($price, $num)
{
return $price * $num;
}
}

// 折扣策略
class CashRebate extends CashSuper
{
public $discount; // 折扣

public function __construct($discount = 10)
{
$this->discount = $discount / 10;
}

public function acceptCach($price, $num)
{
return $price * $num * $this->discount;
}
}

// 满减策略
class CashRereturn extends CashSuper
{
public $flag; //
public $return; //

public function __construct($flag, $return)
{
$this->flag = $flag;
$this->return = $return;
}

public function acceptCach($price, $num)
{
$money = $price * $num;
if ($money >= $this->flag) {
echo 1;
$money = $money - (intval($money / $this->flag) * $this->return);
}

return $money;
}
}

// 此类维护我们的策略
class CashContext
{

public $obj = null;
// 这里传递进来的不是某个策略,而是抽象类类型,因为所有策略都继承于抽象类并实现了计算方法
function __construct(CashSuper $obj)
{
$this->obj = $obj;
}
// 根据传递进来的策略,调用其本身的计算方法
public function getResult($price, $num)
{
return $this->obj->acceptCach($price, $num);
}
}



class Program
{

public function calculate($price, $num, $type = 1, $discount = 0)
{
switch ($type)
{
case 1:
$obj = new CashNormal();
break;

case 2:
echo '享受'. $discount .',';
$obj = new CashRebate($discount);
break;

case 3:
echo '享受满减,';
$obj = new CashRereturn(300, 100);
break;

default:
# code...
break;
}


$totalPrice = (new CashContext($obj))->getResult($price, $num);

echo '单价'. $price .',数量'. $num .',总价:'. $totalPrice ."\n";
return $totalPrice;
}

}

$total = 0;

$program = new Program();

$total += $program->calculate(155, 2);

$total += $program->calculate(102, 3, 2, 8);

$total += $program->calculate(220, 3, 3);

echo '总计:'. $total;

/**

输出结果:

单价155,数量2,总价:310
享受8,单价102,数量3,总价:244.8
享受满减,单价220,数量3,总价:460
总计:1014.8

**/

有问题请Email联系: karlxu0424@gmail.com