ホームページ >バックエンド開発 >PHPチュートリアル >Symfony2 のデザインパターンについて: Decorator パターン

Symfony2 のデザインパターンについて: Decorator パターン

WBOY
WBOYオリジナル
2016-08-08 09:33:141117ブラウズ

デザインパターンとの接触がない場合、プログラミングはデータベースのニュースを読むときは直接データベースベースのメソッドを書くことと、推奨されるニュースを読むときはXMLベースのメソッドを書くことの間に違いはありません。そのとき、私はこのように認識することに何も問題はないと感じました。ただし、これら 2 つのメソッドの実装には多くの類似点があることがわかりますが、どちらもニュース ヘッドラインのコレクションを読み取ってデータ ソースをバインドしますが、データ ソースを取得する方法が異なります。管理を容易にするために、これら 2 つの方法を制限する統一インターフェイスを定義できます。このアプローチは、さまざまなメディアのニュースを読むという要件にも十分対応できます。しかし、ニュースを読むときに他の操作を実行する必要がある場合はどうすればよいでしょうか。たとえば、読んだニュースの人気度に 1 つを追加するなどです。このとき、元のプログラムを修正する必要がありますが、これは「拡張のために開き、修正のために閉じられる」というプログラミングの原則に反します。それを解決するにはどうすればよいでしょうか? ここでデコレータ パターンが役に立ちます。

元のクラス ファイルを変更したり継承を使用したりすることなく、オブジェクトの機能を動的に拡張します。ラッピングオブジェクト、つまり装飾を作成することで、実際のオブジェクトをラッピングします。

デコレーター パターンは、装飾される各関数を別のクラスに配置し、装飾するオブジェクトをこのクラスでラップできるようにします。したがって、特別な動作を実行する必要がある場合、クライアント コードは実行時に必要に応じてオブジェクトをラップすることができます。装飾は一貫した順序で機能します。

図1

使用シナリオ

さまざまな機会に応じて異なる服を着た生徒を作成する必要がある場合を想像してください。たとえば、学校では生徒は制服を着る必要があり、プロムでは生徒はフォーマルな服を着る必要があり、家では生徒は裸の服を着ても構いません(少し倒錯的です)。もちろん、スーパーマンから学んで、外で下着を着用することもできます。この時点で、機会ごとに異なる服装の学生クラスを作成する必要があるのか​​という疑問が生じます。もしうちの子供が、学生服のズボンと下が露出したフォーマルなトップスを着ている人を望んでいたらどうしますか? StudentWithSchoolUniform、StudentWithFormalWear、StudentWithNaked、StudentWithSchoolUniformAndOutSideUnderWear.... 終わりのない授業~~~疲れた!確かに、これによってクラスが爆発的に増え、需要が増えるとクラスは増え続け、システム全体のメンテナンスが困難になることは想像できます。

現時点では、デコレーター モードがその役割を果たすことができます。下着、フォーマルウェア、靴、眼鏡などはすべて、装飾されたオブジェクトと装飾を継承する特定のオブジェクトです。同じ親クラス。生徒に別の服を着せることは、実際には装飾されたクラス(生徒)を包むためにデコレータークラス(衣服)を使用することであり、比喩的に言えば、これはドレスアッププロセスです。

クラスとインターフェース

  • コンポーネント (装飾されたオブジェクトの基本クラス、例の Person クラスに対応)
  • ConcreteComponent (例の Student クラスに対応する、特定の装飾されたオブジェクト)
  • デコレータ(デコレータ基本クラス、例に対応するコスチューム)
  • ContreteDecorator (パンツ、シャツなどの例に対応する特定のデコレータ クラス)

図2

人物.php

リーリー

コードを表示

Student.php

リーリー

コードを表示

コスチューム.php

リーリー

コードを表示

シャツ.php

リーリー

コードを表示

パンツ.php

リーリー

コードを表示

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> }
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> }
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>';

图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> }

 

优点

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

缺点

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

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

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。