Definition of decorator pattern
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 run according to It is necessary to use decoration functions to wrap objects selectively and sequentially.
Picture 1
Usage scenarios
Imagine if we need to create a student with different clothes for different occasions, for example: students at school need to wear school uniforms, students at dances need to wear formal clothes, and students at home can dress naked (a bit perverted) , of course, you can also learn from Superman to wear his 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, and as demand increases, classes will continue to increase, and the maintenance difficulty of the entire system can be imagined.
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 objects to be decorated. The decorated object and the abstract class of the decorator both 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
Example
Picture 2
Person.php
1 php 2 3 /** 4 * Person.php 5 * Decorated base class 6 **/ 7 abstract class Person{ 8 9 public abstract function show(); 10 11 } View CodeStudent.php
1 php 2 3 /** 4 * Student.php 5 * Specific decorated object 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 'I am a student',$this->name; 17 } 18 } View CodeCostume.php
1 php 2 3 /** 4 * Costume.php 5 * Decorator base class 6 **/ 7 abstract class Costume extends Person{ 8 9 10 } View CodeShirt.php
1 php 2 3 /** 4 * Shirt.php 5 * Specific decorator class 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(),',wearing shirt'; 20 } 21 22 } View CodePants.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(),',wearing pants'; 19 } 20 21 } View CodeGlasses.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(),',with glasses'; 19 } 20 21 } View CodeUnderWear.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 CodeClient.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>';
图3 输出结果截图
Symfony2 EventDispatch 组件对装饰者模式的应用
图4 Symfony2 EventDispatch组件使用装饰模式
图5 Framework配置EventDispatcher
具体装饰者对象SymfonyComponentHttpKernelDebugTraceableEventDispatcher::dispatch()方法,核心依旧是调用被装饰的具体对象SymfonyComponentEventDispatcherEventDispatcher::dispatch()方法进行工作,但是装饰者对象SymfonyComponentHttpKernelDebugTraceableEventDispatcher::dispatch()方法添加了相应的功能,例如在调用SymfonyComponentEventDispatcherEventDispatcher::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> }
优点
缺点