關於Symfony2中的設計模式:裝飾者模式

來源:互聯網
上載者:User
在沒有接觸設計模式時,都是針對具體實現編程,讀取資料庫新聞時直接寫一個基於資料庫的方法,讀取推薦新聞時再寫一個基於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教程有興趣的朋友有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.