一、问题
模拟不同课程有不同的收费方式,并且能灵活改变(新增或删减),如讲座可以固定收费也可改为按时收费,研讨会也是。
二、模式简介及关键点
1.在父类代码中使用条件语句是一种退倒,可以用多态来代替条件语句。条件语句有时被称作实现了一个“模拟继承”
2.策略模式适用于将一组算法移入到一个独立的类型中。如例子通过移走费用计算的相关代码,可以简化Lesson类型
3.在合理的模式中,Lesson类不负责计费,而是把计费任务“委托”给CostStrategy类。这种显式调用另一个对象的方法来执行一个请求的方式便是所谓的“委托”
4.让类专注自己的职责。CostStrategy负责计费,Lesson类负责管理课程数据
5.把变化的概念封装起来,本例变化的概念便是费用算法。变化的元素可被提取出来形成子类,而这些元素共同拥有一个抽象父类CostStrategy,这个类可以被其他类使用
三、不好的设计方式
1.定价策略被不同的子类重复实现,我们不得不重复开发功能 ,即使用if语句把定价逻辑移到父类中,也与多态替换条件的重构思想背道而驰
使用if语句把定价逻辑移到父类中后的结构
代码如下:
<?php abstract class Lesson { protected $duration; const FIXED = 1; const TIMED = 2; private $costtype; function __construct( $duration, $costtype=1 ) { $this->duration = $duration; $this->costtype = $costtype; } function cost() { switch ( $this->costtype ) { CASE self::TIMED : return (5 * $this->duration); break; CASE self::FIXED : return 30; break; default: $this->costtype = self::FIXED; return 30; } } function chargeType() { switch ( $this->costtype ) { CASE self::TIMED : return "hourly rate"; break; CASE self::FIXED : return "fixed rate"; break; default: $this->costtype = self::FIXED; return "fixed rate"; } } // more lesson methods... } class Lecture extends Lesson { // Lecture-specific implementations ... } class Seminar extends Lesson { // Seminar-specific implementations ... } $lecture = new Lecture( 5, Lesson::FIXED ); print "{$lecture->cost()} ({$lecture->chargeType()}) "; $seminar= new Seminar( 3, Lesson::TIMED ); print "{$seminar->cost()} ({$seminar->chargeType()}) "; ?>
运行结果:
30 (fixed rate) 15 (hourly rate)
四、策略模式(组合模式)-》把变化的部分(定价)封装
代码如下:
<?php abstract class Lesson { private $duration; private $costStrategy; function __construct( $duration, CostStrategy $strategy ) { $this->duration = $duration; $this->costStrategy = $strategy; } function cost() { return $this->costStrategy->cost( $this ); } function chargeType() { return $this->costStrategy->chargeType( ); } function getDuration() { return $this->duration; } // more lesson methods... } abstract class CostStrategy { abstract function cost( Lesson $lesson ); abstract function chargeType(); } class TimedCostStrategy extends CostStrategy { function cost( Lesson $lesson ) { return ( $lesson->getDuration() * 5 ); } function chargeType() { return "hourly rate"; } } class FixedCostStrategy extends CostStrategy { function cost( Lesson $lesson ) { return 30; } function chargeType() { return "fixed rate"; } } class Lecture extends Lesson { // Lecture-specific implementations ... } class Seminar extends Lesson { // Seminar-specific implementations ... } $lessons[] = new Seminar( 4, new TimedCostStrategy() ); $lessons[] = new Lecture( 4, new FixedCostStrategy() ); foreach ( $lessons as $lesson ) { print "lesson charge {$lesson->cost()}. "; print "Charge type: {$lesson->chargeType()} "; } ?>
运行结果:
lesson charge 20. Charge type: hourly rate lesson charge 30. Charge type: fixed rate
五、另一方面,降低耦合
代码如下:
<?php abstract class Lesson { private $duration; private $costStrategy; function __construct( $duration, CostStrategy $strategy ) { $this->duration = $duration; $this->costStrategy = $strategy; } function cost() { return $this->costStrategy->cost( $this ); } function chargeType() { return $this->costStrategy->chargeType( ); } function getDuration() { return $this->duration; } // more lesson methods... } abstract class CostStrategy { abstract function cost( Lesson $lesson ); abstract function chargeType(); } class TimedCostStrategy extends CostStrategy { function cost( Lesson $lesson ) { return ( $lesson->getDuration() * 5 ); } function chargeType() { return "hourly rate"; } } class FixedCostStrategy extends CostStrategy { function cost( Lesson $lesson ) { return 30; } function chargeType() { return "fixed rate"; } } class Lecture extends Lesson { // Lecture-specific implementations ... } class Seminar extends Lesson { // Seminar-specific implementations ... } class RegistrationMgr { function register( Lesson $lesson ) { // do something with this Lesson // now tell someone $notifier = Notifier::getNotifier(); $notifier->inform( "new lesson: cost ({$lesson->cost()})" ); } } abstract class Notifier { static function getNotifier() { // acquire concrete class according to // configuration or other logic if ( rand(1,2) == 1 ) { return new MailNotifier(); } else { return new TextNotifier(); } } abstract function inform( $message ); } class MailNotifier extends Notifier { function inform( $message ) { print "MAIL notification: {$message} "; } } class TextNotifier extends Notifier { function inform( $message ) { print "TEXT notification: {$message} "; } } $lessons1 = new Seminar( 4, new TimedCostStrategy() ); $lessons2 = new Lecture( 4, new FixedCostStrategy() ); $mgr = new RegistrationMgr(); $mgr->register( $lessons1 ); $mgr->register( $lessons2 ); ?>
运行结果:
TEXT notification: new lesson: cost (20) MAIL notification: new lesson: cost (30)