设计模式之策略模式

假设课程现有固定收费和按小时收费两种收费方式,我们需要根据上课时间计算出收费金额

  1. 首先我们定义一个课程类如下:
class Lesson
{
    protected $duration;
    const FIXED = 1;
    const TIMED = 2;
    private $chargetype;

    public function __construct($duration, $chargetype)
    {
        $this->duration = $duration;
        $this->chargetype = $chargetype;
    }

    public function cost()
    {
        switch ($this->chargetype) {
            case self::FIXED:
                return 30;
                break;
            case self::TIMED:
                return ($this->duration * 5);
                break;
            default:
                $this->chargetype = self::FIXED;
                return 30;
        }
    }

    public function chargeType()
    {
        switch ($this->chargetype) {
            case self::FIXED:
                return '固定收费';
                break;
            case self::TIMED:
                return '小时收费';
                break;
            default:
                $this->chargetype = self::FIXED;
                return '固定收费';
        }
    }
}
  1. 然后有两种课程,收费方式分别为固定收费和按小时收费
/**
 * 固定收费方式
 * Class Lecture
 */
class  Lecture extends Lesson
{

}

/**
 * 按小时收费方式
 * Class Seminar
 */
class  Seminar extends Lesson
{

}

  1. 然后我们实例化类打印出上课五小时的收费金额以及计费方式
$lecture = new Lesson(5, Lesson::FIXED);
$seminar = new Seminar(5, Lesson::TIMED);
print "{$lecture->cost()}({$lecture->chargeType()})\n";
print "{$seminar->cost()}({$seminar->chargeType()})\n";

程序运行结果

30(固定收费) 25(小时收费)

我们在父类里面需要进行条件判断来计算收费结果和方式,如果增加了另外的收费方式,就要对父类进行修改,这样管理起来也不方便,我们可以采用策略模式解决这种问题

  1. 同样我们先定义一个课程类
/**
 * 课程类
 * Class Lesson
 */
class Lesson
{
    private $duration;
    private $stragety;

    public function __construct($duration, Stragety $stragety)
    {
        $this->duration = $duration;
        $this->stragety = $stragety;
    }

    /**
     * 收费金额
     */
    public function cost()
    {
        return $this->stragety->cost($this);
    }

    /**
     * 收费方式
     */
    public function chargeType()
    {
        return $this->stragety->chargeType();
    }

    public function getDuration()
    {
        return $this->duration;
    }
}

此时课程类中cost和chargeType方法并不直接负责计算收费和返回收费方式了,而是将计算收费和获取收费方式委托给其他类(策略类).课程类中需要一个策略类对象作为它的属性.

  1. 需要定义一个策略抽象类
/**
 * 策略抽象类
 * Class Stragety
 */
abstract class Stragety
{
    abstract function cost(Lesson $lesson);

    abstract function chargeType();
}
  1. 不同的收费策略类实现这个抽象类
/**
 * 固定收费策略
 * Class FixedCostStragety
 */
class FixedCostStragety extends Stragety
{
    public function cost(Lesson $lesson)
    {
        return 30;
    }

    public function chargeType()
    {
        return '固定收费';
    }
}

/**
 * 小时收费策略
 * Class TimedCostStragety
 */
class  TimedCostStragety extends Stragety
{
    public function cost(Lesson $lesson)
    {
        return $lesson->getDuration() * 5;
    }

    public function chargeType()
    {
        return '小时收费';
    }
}
  1. 实例化课程类
$lessons[] = new  Lesson(5, new FixedCostStragety());
$lessons[] = new Lesson(5, new TimedCostStragety());
foreach ($lessons as $lesson) {
    print "{$lesson->cost()}({$lesson->chargeType()})\r";
}
  1. 程序运行结果
30(固定收费) 25(小时收费)

运行结果与原来保持一直,我们将计算方式从课程类中提取出来,将具体的计算委托给了策略类,减少了程序之间的耦合,之后再添加其他的计费方式只需要增加一种策略类实现抽象类即可,而不需要改变课程类中的代码.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值