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 相关文章推荐
dedecms中常见问题修改方法总结
Mar 21 PHP
php创建sprite
Feb 11 PHP
destoon安装出现Internal Server Error的解决方法
Jun 21 PHP
php一行代码获取文件后缀名实例分析
Nov 12 PHP
PHP中使用file_get_contents post数据代码例子
Feb 13 PHP
PHP获得数组交集与差集的方法
Jun 10 PHP
前端必学之PHP语法基础
Jan 01 PHP
PHP mysql事务问题实例分析
Jan 18 PHP
php将服务端的文件读出来显示在web页面实例
Oct 31 PHP
PHP简单读取xml文件的方法示例
Apr 20 PHP
ThinkPHP5&amp;5.1实现验证码的生成、使用及点击刷新功能示例
Feb 07 PHP
PHP pthreads v3使用中的一些坑和注意点分析
Feb 21 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采集文章中的图片获取替换到本地(实现代码)
2013/07/08 PHP
PHP与javascript实现变量交互的示例代码
2013/07/23 PHP
PHP遍历目录并返回统计目录大小
2014/06/09 PHP
YII Framework框架教程之国际化实现方法
2016/03/14 PHP
php 中phar包的使用教程详解
2018/10/26 PHP
Laravel实现通过blade模板引擎渲染视图
2019/10/25 PHP
JQuery 图片延迟加载并等比缩放插件
2009/11/09 Javascript
使用隐藏的new来创建对象
2011/03/29 Javascript
jQuery 淡出一个图像到另一个图像的实现代码
2013/06/12 Javascript
JS中捕获console.log()输出的方法
2015/04/16 Javascript
jQuery+formdata实现上传进度特效遇到的问题
2016/02/24 Javascript
如何通过非数字与字符的方式实现PHP WebShell详解
2017/07/02 Javascript
JavaScript多线程运行库Nexus.js详解
2017/12/22 Javascript
在小程序开发中使用npm的方法
2018/10/17 Javascript
Vue CLI 3.x 自动部署项目至服务器的方法
2019/04/02 Javascript
javascript中如何判断类型汇总
2019/05/14 Javascript
Vue-drag-resize 拖拽缩放插件的使用(简单示例)
2019/12/04 Javascript
Python代码的打包与发布详解
2014/07/30 Python
python算法表示概念扫盲教程
2017/04/13 Python
Python操作MySQL数据库的三种方法总结
2018/01/30 Python
python实战之实现excel读取、统计、写入的示例讲解
2018/05/02 Python
python高级特性和高阶函数及使用详解
2018/10/17 Python
python实现维吉尼亚加密法
2019/03/20 Python
Python常用断言函数实例汇总
2020/11/30 Python
使用Python爬取Json数据的示例代码
2020/12/07 Python
彪马加拿大官网:PUMA加拿大
2018/10/04 全球购物
Java Servlet API中forward() 与redirect()的区别
2014/04/20 面试题
大二学生职业生涯规划书
2014/02/05 职场文书
个人租房协议书
2014/04/09 职场文书
公司寄语大全
2014/04/10 职场文书
毕业生找工作自荐书
2014/06/30 职场文书
大学运动会加油稿200字(5篇)
2014/09/27 职场文书
采购员岗位职责
2015/02/03 职场文书
2015年乡镇食品安全工作总结
2015/10/22 职场文书
基于Java的MathML转图片的方法(示例代码)
2021/06/23 Java/Android
Python函数中apply、map、applymap的区别
2021/11/27 Python