PHP组合模式、策略模式
一、问题
模拟不同课程有不同的收费方式,并且能灵活改变(新增或删减),如讲座可以固定收费也可改为按时收费,研讨会也是。
二、模式简介及关键点
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()})\n";
$seminar= new Seminar( 3, Lesson::TIMED );
print "{$seminar->cost()} ({$seminar->chargeType()})\n";
?>
运行结果:
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()}\n";
}
?>
运行结果:
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}\n";
}
}
class TextNotifier extends Notifier {
function inform( $message ) {
print "TEXT notification: {$message}\n";
}
}
$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)
You can do anything you set your mind to, man!

浙公网安备 33010602011771号