策略模式适用于将一组算法移入到一个独立到类型中。通过移走费用计算相关到的代码,可以简化Lesson类型。
我们创建一个名为CostStrategy的抽象类,它定义了抽象方法cost()和chargeType(),cost()方法需要一个Lesson实例,用于生成费用数据。我们提供了CostStrategy的两个实现,因为Lesson对象只需要CostStrategy类型的对象即可工作,不需要指定具体类型的子类,所以我们在任何时候都能通过创建CostStrategy的子类来添加新的费用算法,而这不会要求对任何Lesson类进行修改。
Lesson类的代码:
abstract class Lesson
{
private $duration;
private $costStrategy;
public function __construct($duration, CostStrategy $strategy)
{
$this->duration = $duration;
$this->costStrategy = $strategy;
}
public function cost()
{
return $this->costStrategy->cost($this);
}
public function chargeType()
{
return $this->costStrategy->chargeType();
}
public function getDuration()
{
return $this->duration;
}
}
Lecture类的代码:
class Lecture extends Lesson
{
// Lecture 特定的实现
}
Seminar类的代码:
class Seminar extends Lesson
{
// Seminar 特定的实现
}
Lesson类需要一个作为属性的CostStrategy对象。Lesson::cost() 方法只调用CostStrategy::cost()。Lesson::chargeType() 只调用CostStrategy::chargeType()。这种显示调用另一个对象的方法来执行一个请求的方式便是所谓的“委托”。在我们的示例中,CostStrategy对象便是Lesson的委托方。Lesson类不再负责计费,而是把计费任务传递给CostStrategy类。下面的代码执行了委托操作。
function cost(){
return $this->costStrategy->cost($this);
}
CostStrategy类及其实现子类的代码:
abstract class CostStrategy
{
abstract function cost(Lesson $lesson);
abstract function chargeType();
}
class TimedCostStrategy extends CostStrategy
{
public function cost(Lesson $lesson)
{
return ($lesson->getDuration() * 5);
}
public function chargeType()
{
return "hourly rate";
}
}
class FixedCostStrategy extends CostStrategy
{
public function cost(Lesson $lesson)
{
return 30;
}
public function chargeType()
{
return "fixed rate";
}
}
通过传递不同的CostStrategy 对象,我们可以在代码运行时改变Lesson对象计算费用的方式。这种方式有助于产生具有高度灵活性的代码。动态地组合及重组对象,远胜于将功能静态地建立在代码结构中。
$lessons[] = new \Strategy\Seminar(4, new \Strategy\TimedCostStrategy());
$lessons[] = new \Strategy\Lecture(4, new \Strategy\FixedCostStrategy());
foreach ($lessons as $lesson) {
print "lesson charge {$lesson->cost()} . ";
print "Charge Type : {$lesson->chargeType()} \n";
}
lesson charge 20 . Charge Type : hourly rate
lesson charge 30 . Charge Type : fixed rate
如你所见,此结构的效果之一便是让我们关注类的职责。CostStrategy对象独立负责计算费用,而Lesson对象则负责管理课程数据。
摘自:《深入PHP面向对象、模式与实践【第3版】》