Symfony2中的設計模式——裝飾者模式

裝飾者模式的定義php

   文章連接:http://www.hcoding.com/?p=101ide

  我的站點:http://www.hcoding.com/post

  在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。學習

  裝飾者模式把每一個要裝飾的功能放在單獨的類中,並讓這個類包裝它要裝飾的對象,所以,當須要執行特殊行爲時,客戶端代碼就能夠在運行的時候根據須要有選擇地、按順序地使用裝飾功能包裝對象了。ui

裝飾者模式

圖1this

使用場景spa

  設想一下,若是咱們須要建立一個在不一樣場合有不一樣着裝的學生,例如:在學校學生須要穿上校服,在舞會學生須要穿上正裝,在家學生能夠裸裝(有點變態),固然,還能夠學習超人把底褲穿在外面。這時候問題來了,難道咱們要爲每種場合編寫一個不一樣穿着的學生類嗎?若是咱們的童鞋想要一個穿着校服褲子、正裝上衣外露的底褲怎麼辦?StudentWithSchoolUniform、StudentWithFormalWear、StudentWithNaked、StudentWithSchoolUniformAndOutSideUnderWear..................綿綿無盡的類~~~累!是的,若是這樣就形成類爆炸了,需求增長,類就不斷的增長,整個系統的維護難度可想而知。
pwa

  因此這時候,裝飾者模式就能夠發揮它的做用了,底褲、正裝、校服、鞋子、眼鏡等等都是具體的裝飾者,學生是具體的被裝飾的對象,被裝飾的對象和裝飾者的抽象類都繼承者同一個父類。爲學生穿上不一樣的服裝,其實就是使用裝飾者類(服裝)包裹被裝飾者類(學生),形象的說這是一個穿衣的過程。設計

類和接口3d

  • 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 '<br>';
15 
16     // 用UnderWear類裝飾Person
17     $underwear = new UnderWear($jc);
18     $underwear->show();  // 我是學生JC,穿着DK
19     echo '<br>';
20 
21     // 再用Pants類裝飾Person
22     $pants = new Pants($underwear);
23     $pants->show();   // 我是學生JC,穿着DK,穿着褲子
24     echo '<br>';
25 
26     // 再用Shirt類裝飾Person
27     $shirt = new Shirt($pants);
28     $shirt->show();  // 我是學生JC,穿着DK,穿着褲子,穿着襯衫
29     echo '<br>';
30 
31     // 再用Glasses類裝飾Person
32     $glasses = new Glasses($shirt);
33     $glasses->show();  // 我是學生JC,穿着DK,穿着褲子,穿着襯衫,帶着眼鏡
34     echo '<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():

 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內部發生變化,全部的子類都要改變。
相關文章
相關標籤/搜索