About design patterns in Symfony2: Decorator pattern

WBOY
Release: 2016-08-08 09:33:14
Original
1094 people have browsed it

When there is no contact with design patterns, programming is all about specific implementations. When reading database news, write a database-based method directly, and when reading recommended news, write an XML-based method. There is no difference between the two methods. Relationship. At that time, I felt that there was nothing wrong with realizing it this way. However, you will always find that these two methods have many similarities in implementation. They both read a collection of news headlines to bind the data source, but the methods of fetching the data source are different. In order to facilitate management, we can define a unified interface to constrain these two methods. This approach is also sufficient to meet the requirements for reading news from different media. But what if you need to perform other operations when reading news? For example: add one to the popularity of the news read. At this time, we need to modify the original program, which is contrary to the programming principle of "open for expansion, closed for modification". How to solve it? This is when the decorator pattern comes into play.

Dynamically extend the functionality of an object without changing the original class file and using inheritance. It wraps the real object by creating a wrapping object, that is, decoration.

The decorator pattern puts each function to be decorated in a separate class and lets this class wrap the object it wants to decorate. Therefore, when special behavior needs to be performed, the client code can have choices as needed at runtime. Objects are wrapped using decoration functions in a consistent and sequential manner.

figure 1

Usage scenarios

 Imagine if we need to create a student with different clothes for different occasions, for example: at school students need to wear school uniforms, at prom students need to wear formal clothes, at home students can dress naked (a bit perverted), of course, you can Learn from Superman and wear your underwear outside. At this point the question arises, do we need to write a student class dressed differently for each occasion? What if our kid wants someone wearing school uniform pants and a formal top with exposed bottoms? StudentWithSchoolUniform, StudentWithFormalWear, StudentWithNaked, StudentWithSchoolUniformAndOutSideUnderWear......... Endless classes~~~ Tired! Yes, if this causes an explosion of classes, the demand will increase, and the number of classes will continue to increase. You can imagine how difficult it is to maintain the entire system.

So at this time, the decorator mode can play its role. Underwear, formal wear, school uniforms, shoes, glasses, etc. are all specific decorators. Students are the specific decorated objects. The decorated objects and decorations All abstract classes inherit the same parent class. Wearing different clothes for students is actually using the decorator class (clothing) to wrap the decorated class (students). To put it figuratively, this is a dressing process.

Classes and Interfaces

  • Component (the base class of the decorated object, corresponding to the Person class of the example)
  • ConcreteComponent (specific decorated object, corresponding to the Student class of the example)
  • Decorator (decorator base class, Costume corresponding to the example)
  • ContreteDecorator (specific decorator class, corresponding to examples of Pants, Shirt, etc.)

Example

figure 2

Person.php

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

View Code

Student.php

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

Costume.php

<span> 1</span> <?<span>php </span><span> 2</span> <span> 3</span> <span>/*</span><span>* </span><span> 4</span> <span>*    Costume.php </span><span> 5</span> <span>*    装饰者基类 </span><span> 6</span> <span>*</span><span>*/</span> <span> 7</span> <span>abstract</span> <span>class</span> Costume <span>extends</span><span> Person{ </span><span> 8</span> <span> 9</span> <span>10</span> }
Copy after login

View Code

Shirt.php

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

Pants.php

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

Glasses.php

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

UnderWear.php

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

Client.php

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

图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():

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

 

优点

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

缺点

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

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

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template