PHP设计模式-策略模式

策略模式适用于将一组算法移入到一个独立到类型中。通过移走费用计算相关到的代码,可以简化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版】》