PHP设计模式之装饰者模式


Posted in PHP onFebruary 29, 2012

介绍
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

思维导图

PHP设计模式之装饰者模式

 

有这样一个项目,做一个餐厅订餐系统。起初的代码结构是这样的。前面有很多Beverage的继承类,现在遇到的问题是牛奶的价钱上涨了,那么所有相关的类,我们都要进行调整,比如Milk,SugarAndMilk类,这种类还有很多,我们需要逐个去修改类中的方法——开发人员每次都做这种事情,要疯了!所以我们要改变现有的结构。以下的图都是简图,实际的图,可没有这么简单。

 

PHP设计模式之装饰者模式

 

 设计问题:

1》类数量爆炸,有很多类,难以维护;
2》整个设计呆板;
3》基类加入的新功能无法使用于子类;
复用类方法的方式很多,比如继承,组合,委托。为什么老是习惯用继承呢?我看Zend Framework也有这种习惯!每次找对应方法,一直往上翻。——题外话!!!!
后来经过小组研究决定,我们决定把基础类抽出来,比如,我们把咖啡做成一个单独的类,其他的咖啡,比如牛奶咖啡,甜味咖啡,我们只对材料单独包装成一个类。
经过改良的设计:

PHP设计模式之装饰者模式

详解
1》对于饮品,我们直接继承Beverage类,直接把报价写进饮品类里面;
2》而对于一些需要添加调味品的特殊饮品,我们做累加操作。比如,我想要杯奶咖啡,则 总价=咖啡价+奶价
3》这样不同的饮料就很容易知道它的价格。
代码

<?php 
abstract class Beverage{ 
public $_name; 
abstract public function Cost(); 
} 
// 被装饰者类 
class Coffee extends Beverage{ 
public function __construct(){ 
$this->_name = 'Coffee'; 
} 
public function Cost(){ 
return 1.00; 
} 
} 
// 以下三个类是装饰者相关类 
class CondimentDecorator extends Beverage{ 
public function __construct(){ 
$this->_name = 'Condiment'; 
} 
public function Cost(){ 
return 0.1; 
} 
} 
class Milk extends CondimentDecorator{ 
public $_beverage; 
public function __construct($beverage){ 
$this->_name = 'Milk'; 
if($beverage instanceof Beverage){ 
$this->_beverage = $beverage; 
}else 
exit('Failure'); 
} 
public function Cost(){ 
return $this->_beverage->Cost() + 0.2; 
} 
} 
class Sugar extends CondimentDecorator{ 
public $_beverage; 
public function __construct($beverage){ 
$this->_name = 'Sugar'; 
if($beverage instanceof Beverage){ 
$this->_beverage = $beverage; 
}else{ 
exit('Failure'); 
} 
} 
public function Cost(){ 
return $this->_beverage->Cost() + 0.2; 
} 
} 
// Test Case 
//1.拿杯咖啡 
$coffee = new Coffee(); 
//2.加点牛奶 
$coffee = new Milk($coffee); 
//3.加点糖 
$coffee = new Sugar($coffee); 
printf("Coffee Total:%0.2f元\n",$coffee->Cost());

总结
1.装饰者(Milk)和被装饰者(Coffee)必须是一样的类型。目的是装饰者必须取代被装饰者。
2.添加行为:当装饰者和组件组合时,就是在加入新的行为。
题外话:
1.利用继承设计子类行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。打个比方,老子想学点功夫,看你小子会太极拳,老子只需要继承你一下 ,老子也就会太极拳了——呵呵,这时老子就变成你儿子了,看来继承是要付出代价的。
2.组合,我们可以扩展对象的行为,在运行时动态地进行扩展。利用组合我们可以随时把我们当时设计超类时没有想到的方法加入到对象中,而不用改变现有的代码。打个比方,老子现在没有内力,吸功大法,把和尚,尼姑,道士的内力(行为对象)都吸过来,那在搏斗(运行时)中,老子可以随时都能使用不同的内力,但也不能胡乱吸内力,否则你就要走火入魔了!
3.类应该对扩展开放,对修改关闭。如果我们每个部分都用装饰者模式进行设计,那么对于整个框架来说有点浪费,而且你也加大了代码的难度。那什么时候使用这种模式呢?我们一般用于经常改变的地方。那我们又怎么知道哪些是经常改变的地方呢?这个就需要我们的经验和你对所处行业的了解。建议大家平时多看点例子。
4.装饰模式为设计注入弹性,但同时会在设计中加入大量的小类,这偶尔会导致别人不容易了解这种设计。
5.在使用装饰者模式的时候,对插入的的装饰者要特别小心。因为装饰者模式依赖某种特定的类型(Beverage)。
6.要想很好的使用装饰者模式,我们还要配合使用工厂模式和生成器模式,但今天只说装饰者模式。要想知道更多,请听下回分解。
参考文献:《head first 设计模式》
PHP 相关文章推荐
MySQL相关说明
Jan 15 PHP
PHP类的静态(static)方法和静态(static)变量使用介绍
Feb 19 PHP
用PHP+MySQL搭建聊天室功能实例代码
Aug 20 PHP
让CodeIgniter的ellipsize()支持中文截断的方法
Jun 12 PHP
PHP常用正则表达式集锦
Aug 17 PHP
php获取文章上一页与下一页的方法
Dec 01 PHP
Zend Framework教程之响应对象的封装Zend_Controller_Response实例详解
Mar 07 PHP
thinkPHP模板中for循环与switch语句用法示例
Nov 30 PHP
php正则提取html图片(img)src地址与任意属性的方法
Feb 08 PHP
PHP fprintf()函数用法讲解
Feb 16 PHP
PHP封装类似thinkphp连贯操作数据库Db类与简单应用示例
May 08 PHP
不常用但很实用的PHP预定义变量分析
Jun 25 PHP
php preg_filter执行一个正则表达式搜索和替换
Feb 27 #PHP
mysql总结之explain
Feb 27 #PHP
php&amp;mysql 日期操作小记
Feb 27 #PHP
MySQL时间字段究竟使用INT还是DateTime的说明
Feb 27 #PHP
php explode函数实例代码
Feb 27 #PHP
PHP中获取文件扩展名的N种方法小结
Feb 27 #PHP
PHP中的正则表达式函数介绍
Feb 27 #PHP
You might like
PHP资源管理框架Assetic简介
2014/06/12 PHP
yii框架结合charjs统计上一年与当前年数据的方法示例
2020/04/04 PHP
Some tips of wmi scripting in jscript (1)
2007/04/03 Javascript
JavaScript DOM学习第四章 getElementByTagNames
2010/02/19 Javascript
Bookmarklet实现启动jQuery(模仿 云输入法)
2010/09/15 Javascript
JS获取整个页面文档的实现代码
2011/12/15 Javascript
javascript作用域和闭包使用详解
2014/04/25 Javascript
下拉框select的绑定示例
2014/09/04 Javascript
jquery中val()方法是从最后一个选项往前读取的
2015/09/06 Javascript
angularjs学习笔记之简单介绍
2015/09/26 Javascript
js数组常见操作及数组与字符串相互转化实例详解
2015/11/10 Javascript
jQuery中ajax的load()与post()方法实例详解
2016/01/05 Javascript
Vue.js中轻松解决v-for执行出错的三个方案
2017/06/09 Javascript
Vue单文件组件的如何使用方式介绍
2017/07/28 Javascript
trackingjs+websocket+百度人脸识别API实现人脸签到
2018/11/26 Javascript
微信小程序template模板与component组件的区别和使用详解
2019/05/22 Javascript
微信小程序—setTimeOut定时器的问题及解决
2019/07/26 Javascript
js贪心算法 钱币找零问题代码实例
2019/09/11 Javascript
JavaScript修改注册表实例代码
2020/01/05 Javascript
Node.js API详解之 V8模块用法实例分析
2020/06/05 Javascript
使用JavaScript和MQTT开发物联网应用示例解析
2020/08/07 Javascript
浅谈vue中resetFields()使用注意事项
2020/08/12 Javascript
详解详解Python中writelines()方法的使用
2015/05/25 Python
Python3.5 + sklearn利用SVM自动识别字母验证码方法示例
2019/05/10 Python
PyPDF2读取PDF文件内容保存到本地TXT实例
2020/05/12 Python
全球地下的服装和态度:Slam Jam
2018/02/04 全球购物
Becextech新西兰:数码单反相机和手机在线商店
2018/04/27 全球购物
印度手工编织服装和家居用品商店:Fabindi
2019/10/07 全球购物
平面设计师的工作职责
2013/11/21 职场文书
银行职业规划书范文
2013/12/28 职场文书
经销商年会策划方案
2014/05/29 职场文书
2014年小学数学教师工作总结
2014/12/03 职场文书
药店收银员岗位职责
2015/04/07 职场文书
2015年超市员工工作总结
2015/05/04 职场文书
教师远程研修感悟
2015/11/18 职场文书
win10输入法不见了只能打出字母怎么解决?
2022/08/05 数码科技