0

0

关于Symfony2中的设计模式:装饰者模式

php中文网

php中文网

发布时间:2016-08-08 09:33:14

|

1166人浏览过

|

来源于php中文网

原创

在没有接触设计模式时,都是针对具体实现编程,读取数据库新闻时直接写一个基于数据库的方法,读取推荐新闻时再写一个基于XML的方法,两种方法之间没有任何的关系.当时觉的这样实现也没什么不好。可是你总会发现这两种方法在实现上有很多相同的地方,都是读取出一个新闻标题集合来绑定数据源,只是取数据源的方法不同而已。为了方便管理,我们可以定义一个统一的接口来约束这两种方法。这种做法也足够满足读取不同载体的新闻要求。可是如果在读取新闻时要做其它的操作呢?例如:给读取出来的新闻的人气加一。这个时候我们就要修改原程序,这样有背于"对扩展开放,对修改关闭"的编程原则。如何解决呢?这就是装饰者模式出场的时候了。

  在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

  装饰者模式把每个要装饰的功能放在单独的类中,并让这个类包装它要装饰的对象,因此,当需要执行特殊行为时,客户端代码就可以在运行的时候根据需要有选择地、按顺序地使用装饰功能包装对象了。

图1

使用场景

  设想一下,如果我们需要创建一个在不同场合有不同着装的学生,例如:在学校学生需要穿上校服,在舞会学生需要穿上正装,在家学生可以裸装(有点变态),当然,还可以学习超人把底裤穿在外面。这时候问题来了,难道我们要为每种场合编写一个不同穿着的学生类吗?如果我们的童鞋想要一个穿着校服裤子、正装上衣外露的底裤怎么办?StudentWithSchoolUniform、StudentWithFormalWear、StudentWithNaked、StudentWithSchoolUniformAndOutSideUnderWear..................绵绵无尽的类~~~累!是的,如果这样就造成类爆炸了,需求增加,类就不断的增加,整个系统的维护难度可想而知。

  所以这时候,装饰者模式就可以发挥它的作用了,底裤、正装、校服、鞋子、眼镜等等都是具体的装饰者,学生是具体的被装饰的对象,被装饰的对象和装饰者的抽象类都继承者同一个父类。为学生穿上不同的服装,其实就是使用装饰者类(服装)包裹被装饰者类(学生),形象的说这是一个穿衣的过程。

类和接口

  • Component(被装饰对象基类,对应例子的Person类)
  • ConcreteComponent(具体被装饰对象,对应例子的Student类)
  • Decorator(装饰者基类,对应例子的Costume)
  • ContreteDecorator(具体的装饰者类,对应例子的Pants、Shirt等)

例子

 

图2 

Person.php

 1 php  2  3 /**  4 *    Person.php  5 *   被装饰基类  6 **/  7 abstract class Person{  8  9 public abstract function show(); 10 11 }

View Code

Student.php

 1 php  2  3 /**  4 *    Student.php  5 *    具体被装饰对象  6 **/  7 class Student extends Person{  8  9 private $name; 10 11 public function __construct($name){ 12 $this->name = $name; 13  } 14 15 public function show(){ 16 echo '我是学生',$this->name; 17  } 18 }

View Code

Costume.php

 1 php  2  3 /**  4 *    Costume.php  5 *    装饰者基类  6 **/  7 abstract class Costume extends Person{  8  9 10 }

View Code

Shirt.php

 1 php  2  3 /**  4 *    Shirt.php  5 *    具体的装饰者类  6 **/  7 class Shirt extends Costume{  8  9 private $person; 10 11 public function __construct(Person $person){ 12 13 $this->person = $person; 14 15  } 16 17 public function show(){ 18 19 echo $this->person->show(),',穿着衬衫'; 20  } 21 22 }

View Code

Pants.php

 1 php  2  3 /**  4 *    Pants.php  5 **/  6 class Pants extends Costume{  7  8 private $person;  9 10 public function __construct(Person $person){ 11 12 $this->person = $person; 13 14  } 15 16 public function show(){ 17 18 echo $this->person->show(),',穿着裤子'; 19  } 20 21 }

View Code

Glasses.php

 1 php  2  3 /**  4 *    Glasses.php  5 **/  6 class Glasses extends Costume{  7  8 private $person;  9 10 public function __construct(Person $person){ 11 12 $this->person = $person; 13 14  } 15 16 public function show(){ 17 18 echo $this->person->show(),',带着眼镜'; 19  } 20 21 }

View Code

UnderWear.php

 1 php  2  3 /**  4 *    UnderWear.php  5 **/  6 class UnderWear extends Costume{  7  8 private $person;  9 10 public function __construct(Person $person){ 11 12 $this->person = $person; 13 14  } 15 16 public function show(){ 17 18 echo $this->person->show(),',穿着DK'; 19  } 20 21 }

View Code

Client.php

 1 php  2  3 require_once 'Person.php';  4 require_once 'Costume.php';  5 require_once 'Student.php';  6 require_once 'UnderWear.php';  7 require_once 'Shirt.php';  8 require_once 'Pants.php';  9 require_once 'Glasses.php'; 10 11 // Student继承Person 12 $jc = new Student('JC'); 13 $jc->show(); // 我是学生JC 14 echo '
'; 15 16 // 用UnderWear类装饰Person 17 $underwear = new UnderWear($jc); 18 $underwear->show(); // 我是学生JC,穿着DK 19 echo '
'; 20 21 // 再用Pants类装饰Person 22 $pants = new Pants($underwear); 23 $pants->show(); // 我是学生JC,穿着DK,穿着裤子 24 echo '
'; 25 26 // 再用Shirt类装饰Person 27 $shirt = new Shirt($pants); 28 $shirt->show(); // 我是学生JC,穿着DK,穿着裤子,穿着衬衫 29 echo '
'; 30 31 // 再用Glasses类装饰Person 32 $glasses = new Glasses($shirt); 33 $glasses->show(); // 我是学生JC,穿着DK,穿着裤子,穿着衬衫,带着眼镜 34 echo '
';

图3 输出结果截图

Symfony2 EventDispatch 组件对装饰者模式的应用

 

图4 Symfony2 EventDispatch组件使用装饰模式

图5 Framework配置EventDispatcher

 

  • Symfony\Component\EventDispatcher\EventDispatcherInterface 是被装饰的接口
  • Symfony\Component\EventDispatcher\EventDispatcher 和 Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher 是被装饰的具体对象
  • Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface 装饰者接口
  • Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher 装饰者基类
  • Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher 具体的装饰者对象

  具体装饰者对象Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher::dispatch()方法,核心依旧是调用被装饰的具体对象Symfony\Component\EventDispatcher\EventDispatcher::dispatch()方法进行工作,但是装饰者对象Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher::dispatch()方法添加了相应的功能,例如在调用Symfony\Component\EventDispatcher\EventDispatcher::dispatch()方法前后分别调用了preProcess()、preDispatch()和postDispatch()、postProcess():

 1 /**  2  * {@inheritdoc}  3 */  4 public function dispatch($eventName, Event $event = null)  5  {  6 if (null === $event) {  7 $event = new Event();  8  }  9 10 // 装饰者对象增加的功能 11 $this->preProcess($eventName); 12 $this->preDispatch($eventName, $event); 13 14 $e = $this->stopwatch->start($eventName, 'section'); 15 16 // 核心依旧是调用被装饰的具体对象Symfony\Component\EventDispatcher\EventDispatcher::dispatch()方法 17 $this->dispatcher->dispatch($eventName, $event); 18 19 if ($e->isStarted()) { 20 $e->stop(); 21  } 22 23 // 装饰者对象增加的功能 24 $this->postDispatch($eventName, $event); 25 $this->postProcess($eventName); 26 27 return $event; 28 }

 

优点

  1.  通过组合而非继承的方式,实现了动态扩展对象的功能的能力。
  2. 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
  3. 充分利用了继承和组合的长处和短处,在灵活性和扩展性之间找到完美的平衡点。
  4.  装饰者和被装饰者之间虽然都是同一类型,但是它们彼此是完全独立并可以各自独立任意改变的。
  5. 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

缺点

  1. 装饰链不能过长,否则会影响效率。
  2. 只在必要的时候使用装饰者模式,否则会提高程序的复杂性,增加系统维护难度。
  3. 装饰者对象和被装饰者对象都继承Component,如果Component内部发生变化,所有的子类都要改变。

以上就介绍了关于Symfony2中的设计模式:装饰者模式,包括了Symfony2,装饰者模式方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 序列化
Python 序列化

本专题整合了python序列化、反序列化相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.02.02

AO3官网入口与中文阅读设置 AO3网页版使用与访问
AO3官网入口与中文阅读设置 AO3网页版使用与访问

本专题围绕 Archive of Our Own(AO3)官网入口展开,系统整理 AO3 最新可用官网地址、网页版访问方式、正确打开链接的方法,并详细讲解 AO3 中文界面设置、阅读语言切换及基础使用流程,帮助用户稳定访问 AO3 官网,高效完成中文阅读与作品浏览。

91

2026.02.02

主流快递单号查询入口 实时物流进度一站式追踪专题
主流快递单号查询入口 实时物流进度一站式追踪专题

本专题聚合极兔快递、京东快递、中通快递、圆通快递、韵达快递等主流物流平台的单号查询与运单追踪内容,重点解决单号查询、手机号查物流、官网入口直达、包裹进度实时追踪等高频问题,帮助用户快速获取最新物流状态,提升查件效率与使用体验。

27

2026.02.02

Golang WebAssembly(WASM)开发入门
Golang WebAssembly(WASM)开发入门

本专题系统讲解 Golang 在 WebAssembly(WASM)开发中的实践方法,涵盖 WASM 基础原理、Go 编译到 WASM 的流程、与 JavaScript 的交互方式、性能与体积优化,以及典型应用场景(如前端计算、跨平台模块)。帮助开发者掌握 Go 在新一代 Web 技术栈中的应用能力。

11

2026.02.02

PHP Swoole 高性能服务开发
PHP Swoole 高性能服务开发

本专题聚焦 PHP Swoole 扩展在高性能服务端开发中的应用,系统讲解协程模型、异步IO、TCP/HTTP/WebSocket服务器、进程与任务管理、常驻内存架构设计。通过实战案例,帮助开发者掌握 使用 PHP 构建高并发、低延迟服务端应用的工程化能力。

5

2026.02.02

Java JNI 与本地代码交互实战
Java JNI 与本地代码交互实战

本专题系统讲解 Java 通过 JNI 调用 C/C++ 本地代码的核心机制,涵盖 JNI 基本原理、数据类型映射、内存管理、异常处理、性能优化策略以及典型应用场景(如高性能计算、底层库封装)。通过实战示例,帮助开发者掌握 Java 与本地代码混合开发的完整流程。

5

2026.02.02

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

62

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

55

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

27

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 10.8万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号