PHP设计模式之装饰者模式

所属分类: 网络编程 / PHP编程 阅读数: 1760
收藏 0 赞 0 分享
介绍
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

思维导图

装饰者模式

 

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

 

 

 设计问题:

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

详解
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导出CSV抽象类实例

这篇文章主要介绍了php导出CSV抽象类及其用法示例,可实现循环导出功能,从而避免内存不足的问题,需要的朋友可以参考下
收藏 0 赞 0 分享

php实现的zip文件内容比较类

这篇文章主要介绍了php实现的zip文件内容比较类及其用法,可实现比较两个zip文件的内容,返回新增、删除、及相同的文件列表,是非常实用的技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

php实现获取及设置用户访问页面语言类

这篇文章主要介绍了php实现获取及设置用户访问页面语言类,可实现获取/设置用户访问的页面语言,如果用户没有设置访问语言,则读取Accept-Language,需要的朋友可以参考下
收藏 0 赞 0 分享

PHP+FFMPEG实现将视频自动转码成H264标准Mp4文件

最近做一个在线教学网的项目,需要实现上传任意格式视频自动为h264标准视频,使用html5播放。最终使用PHP+FFMPEG实现,在此将详细解决方案分享给大家!
收藏 0 赞 0 分享

PHP会话控制:Session与Cookie详解

这篇文章主要介绍了PHP会话控制:Session与Cookie详解,本文详细讲解了PHP中Session与Cookie的相关知识,涵盖面较广,需要的朋友可以参考下
收藏 0 赞 0 分享

PHP实现手机号码中间四位用星号(*)隐藏的自定义函数分享

这篇文章主要介绍了PHP实现手机号码中间四位用星号(*)隐藏的自定义函数分享,这是一个比较常用的功能,需要的朋友可以参考下
收藏 0 赞 0 分享

PHP获取mysql数据表的字段名称和详细信息的方法

这篇文章主要介绍了PHP获取mysql数据表的字段名称和详细信息的方法,本文同时还给出了获取数据表结构、列出数据库数据表等方法,需要的朋友可以参考下
收藏 0 赞 0 分享

PHP中的output_buffering详细介绍

这篇文章主要介绍了PHP中的output_buffering详细介绍,本文讲解了output buffering的一些高级用法,需要的朋友可以参考下
收藏 0 赞 0 分享

PHP错误Warning: Cannot modify header information - headers already sent by解决方法

这篇文章主要介绍了PHP错误Warning: Cannot modify header information - headers already sent by解决方法,需要的朋友可以参考下
收藏 0 赞 0 分享

PHP常用编译参数中文说明

这篇文章主要介绍了PHP常用编译参数中文说明,本文用详细的中文注解了PHP编译参数的作用,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多