<?PHP //裝飾模式定義:在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。 //裝飾模式的特色: // (1) 裝飾對象和真實對象有相同的接口。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互。 // (2) 裝飾對象包含一個真實對象的引用(reference) // (3) 裝飾對象接受全部來自客戶端的請求。它把這些請求轉發給真實的對象。 // (4) 裝飾對象能夠在轉發這些請求之前或之後增長一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就能夠在外部增長附加的功能。在面向對象的設計中,一般是經過繼承來實現對給定類的功能擴展。 //適用性: // 如下狀況使用Decorator模式 // 1. 須要擴展一個類的功能,或給一個類添加附加職責。 // 2. 須要動態的給一個對象添加功能,這些功能能夠再動態的撤銷。 // 3. 須要增長由一些基本功能的排列組合而產生的很是大量的功能,從而使繼承關係變的不現實。 // 4. 當不能採用生成子類的方法進行擴充時。一種狀況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類。 // 優勢: // 1. Decorator模式與繼承關係的目的都是要擴展對象的功能,可是Decorator能夠提供比繼承更多的靈活性。 // 2. 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,設計師能夠創造出不少不一樣行爲的組合。 // 缺點: // 1. 這種比繼承更加靈活機動的特性,也同時意味着更加多的複雜性。 // 2. 裝飾模式會致使設計中出現許多小類,若是過分使用,會使程序變得很複雜。 // 3. 裝飾模式是針對抽象組件(Component)類型編程。可是,若是你要針對具體組件編程時,就應該從新思考你的應用架構,以及裝飾者是否合適。固然也能夠改變Component接口,增長新的公開的行爲,實現「半透明」的裝飾者模式。在實際項目中要作出最佳選擇。 // 設計原則: // 1. 多用組合,少用繼承。 // 利用繼承設計子類的行爲,是在編譯時靜態決定的,並且全部的子類都會繼承到相同的行爲。然而,若是可以利用組合的作法擴展對象的行爲,就能夠在運行時動態地進行擴展。 // 2. 類應設計的對擴展開放,對修改關閉。 // 裝飾者與適配者模式的區別編輯 // 1.關於新職責:適配器也能夠在轉換時增長新的職責,但主要目的不在此。裝飾者模式主要是給被裝飾者增長新職責的。 // 2.關於原接口:適配器模式是用新接口來調用原接口,原接口對新系統是不可見或者說不可用的。裝飾者模式原封不動的使用原接口,系統對裝飾的對象也經過原接口來完成使用。(增長新接口的裝飾者模式能夠認爲是其變種--「半透明」裝飾者) // 3.關於其包裹的對象:適配器是知道被適配者的詳細狀況的(就是那個類或那個接口)。裝飾者只知道其接口是什麼,至於其具體類型(是基類仍是其餘派生類)只有在運行期間才知道。[1] /** * 裝扮抽象類 裝扮子類繼承實現打扮方法 */ abstract class Decorate{ //定義被裝扮人對象引用 protected $presonObj; public function __construct($presonObj){ $this->presonObj = $presonObj; } //強制子類實現打扮方法 abstract public function dress(); } /** * 裝扮類1 */ class Decorate1 extends Decorate{ public function dress(){ echo "我是裝扮方法1".PHP_EOL; $this->presonObj->dress(); } } /** * 裝扮類2 */ class Decorate2 extends Decorate{ public function dress(){ echo "我是裝扮方法2".PHP_EOL; $this->presonObj->dress(); } } /** * 裝扮類3 */ class Decorate3 extends Decorate{ public function dress(){ echo "我是裝扮方法3".PHP_EOL; $this->presonObj->dress(); } } /** * 被裝扮類 */ class Presona { private $name; public function __construct($name){ $this->name = $name; } public function dress(){ echo "個人名字:".$this->name."裝扮完畢".PHP_EOL; } } //客戶端調用,注意:這裏是累計調用,以棧的形式,先進後出 $presona = new Presona("小菜"); $presona = new Decorate3($presona); $presona = new Decorate2($presona); $presona = new Decorate1($presona); $presona->dress();