假设课程现有固定收费和按小时收费两种收费方式,我们需要根据上课时间计算出收费金额
- 首先我们定义一个课程类如下:
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 '固定收费';
}
}
}
- 然后有两种课程,收费方式分别为固定收费和按小时收费
/**
* 固定收费方式
* Class Lecture
*/
class Lecture extends Lesson
{
}
/**
* 按小时收费方式
* Class Seminar
*/
class Seminar extends Lesson
{
}
- 然后我们实例化类打印出上课五小时的收费金额以及计费方式
$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(小时收费)
我们在父类里面需要进行条件判断来计算收费结果和方式,如果增加了另外的收费方式,就要对父类进行修改,这样管理起来也不方便,我们可以采用策略模式解决这种问题
- 同样我们先定义一个课程类
/**
* 课程类
* 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方法并不直接负责计算收费和返回收费方式了,而是将计算收费和获取收费方式委托给其他类(策略类).课程类中需要一个策略类对象作为它的属性.
- 需要定义一个策略抽象类
/**
* 策略抽象类
* Class Stragety
*/
abstract class Stragety
{
abstract function cost(Lesson $lesson);
abstract function chargeType();
}
- 不同的收费策略类实现这个抽象类
/**
* 固定收费策略
* 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 '小时收费';
}
}
- 实例化课程类
$lessons[] = new Lesson(5, new FixedCostStragety());
$lessons[] = new Lesson(5, new TimedCostStragety());
foreach ($lessons as $lesson) {
print "{$lesson->cost()}({$lesson->chargeType()})\r";
}
- 程序运行结果
30(固定收费) 25(小时收费)
运行结果与原来保持一直,我们将计算方式从课程类中提取出来,将具体的计算委托给了策略类,减少了程序之间的耦合,之后再添加其他的计费方式只需要增加一种策略类实现抽象类即可,而不需要改变课程类中的代码.