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)
PHP组合模式、策略模式的更多相关文章
- 3.js模式-策略模式
1. 策略模式 策略模式定义一系列的算法,把它们封装起来,并且可以互相替换. var strategies = { isNonEmpty: function(value,errMsg){ if(val ...
- 命令模式 & 策略模式 & 模板方法
一.策略模式 策略模式:封装易变化的算法,可互相替换. GoF<设计模式>中说道:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换.该模式使得算法可独立于它们的客户变化. 比如 ...
- 工厂模式&策略模式。
抽象.封装,具体事情做得越多,越容易犯错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,犯错误可能性就越少.好象我们从编程序中也能悟出人生道理.(百度百科) 不断抽象封装 ...
- 简单工厂模式&策略模式-简介与区别
不得不说,这两种模式真的很像. 相似点:都用到了面向对象的继承.多态.抽象,都拥有相似的结构. 不同点:工厂模式仅提供具体的实例对象,怎么使用这个对象是client的自由,策略模式client可以通过 ...
- java设计模式--行为型模式--策略模式
策略模式: 策略模式 概述 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 适用性 1.许多相关的类仅仅是行为有异.“策略”提供了一种用多个行 ...
- [Python模式]策略模式
策略模式 定义了算法族,分别封装起来,让它们之间可以互相替换.此模式让算法的变化独立于使用算法的客户. 作为动态语言,Python实现策略模式非常容易,只要所有算法提供相同的函数即可. import ...
- <大话设计模式>工厂模式,策略模式
第一章:工厂模式: 通过封装,继承,多态解耦合 业务逻辑和界面逻辑分开 用单独的类创造实例,工厂:创造实例 工厂模式还可以用反射来实现,nsstringFromClass UML类图 聚合表示一众弱的 ...
- 设计模式之——浅谈strategy模式(策略模式)
strategy模式,即策略模式.个人觉得吧,策略模式更多的是一种思维方式. 首先我们要知道,为什么需要策略模式.举个例子,比如用程序输出今天下午去玩什么. PlayGame 玩游戏 package ...
- [19/05/01-星期三] GOF23_行为型模式(策略模式、模板方法模式)
一.策略模式(strategy) [策略接口] /*** * "策略"接口 */ package cn.sxt.strategy; public interface Strateg ...
- Go---设计模式(策略模式)
策略模式定义了算法家族,在调用算法家族的时候不感知算法的变化,客户也不会受到影响. 下面用<大话设计模式>中的一个实例进行改写. 例:超市中经常进行促销活动,促销活动的促销方法就是一个个策 ...
随机推荐
- 46.谈谈SDRAM的作用
SDRAM这个至今还在用的存储器,虽然被后来的DDR取代,掌握好它还是很重要的.之前在调试时,确实费了好大劲,它的复杂性毋庸置疑,一般人要想弄懂他,得花1个月左右吧,至少我这么认为.话说回来,SDRA ...
- maven属性
Maven内置了三大特性:属性.Profile和资源过滤来支持构建的灵活性. 内置属性:主要有两个常用内置属性 ${basedir}表示项目根目录,即包含pom.xml文件的目录 ${version} ...
- 微软Hololens学院教程-Hologram 220-空间声音(Spatial sound )【本文是老版本,与最新的微软教程有出入】
这是老版本的教程,为了不耽误大家的时间,请直接看原文,本文仅供参考哦! 原文链接https://developer.microsoft.com/EN-US/WINDOWS/HOLOGRAPHIC/ho ...
- Netsharp快速入门(之5) 基础档案(之D 实体建模 生成实体代码、同步数据库、配置插件运行时)
作者:秋时 杨昶 时间:2014-02-15 转载须说明出处 3.3.1 同步数据库并生成dll文件 1.在基础档案和销售管理项目上右击,选择同步数据库结构来创建数据库表 2. 在基础档案项目 ...
- Netsharp快速入门(之15) 销售管理(报表B 销售季度表)
作者:秋时 杨昶 转载须说明出处 4.6.2 销售季度表(交叉表) 1.1.1.1 交叉表带数据源和不带数据源区别 带数据源的可以自定义数据源,可以从实体,也可以从Sql脚本得到数据源,并能自定 ...
- 删除vlan的方法
方法一: 删除VLAN 先删接口 switch(config)#int ra f0/1 - 5 switch(config-if)#no switchport access v ...
- WKWebView 与 UIWebView
apple和google为webkit该浏览器引擎的发扬光大做出了重要贡献,在WWDC 2014发布会上发布iOS 8中,apple公布了WebKit框架,这意味着OSX和IOS开发者将共用同样的开发 ...
- foxmail收发gmail彻底失败
周一一上班,发现gmail无法收取邮件,刚开始以为网络不稳定,后来经过百度发现原因是 gmail邮箱也被屏蔽了. 虽然可以FQ,保证gmail邮箱暂时使用,但是不可否认,在当前的形势下, ...
- UVA 10004 Bicoloring
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=12&pa ...
- 【BZOJ】【3238】【AHOI2013】diff(差异)
题目链接:www.lydsy.com/JudgeOnline/problem.php?id=3238 后缀数组 这题题面给的暗示性就很强啊……一看就是要用后缀xx一家的算法,由于本蒻只会后缀数组所以就 ...