摘要:通常有兩種方式可以實現給一個類或對象增加行為繼承機制,使用繼承機制是給現有類添加功能的一種有效途徑,通過繼承一個現有類可以使得子類在擁有自身方法的同時還擁有父類的方法。
裝飾模式 (Decorator Pattern)
裝飾模式能夠實現動態(tài)的為對象添加功能,是從一個對象外部來給對象添加功能。通常有兩種方式可以實現給一個類或對象增加行為:
繼承機制,使用繼承機制是給現有類添加功能的一種有效途徑,通過繼承一個現有類可以使得子類在擁有自身方法的同時還擁有父類的方法。但是這種方法是靜態(tài)的,用戶不能控制增加行為的方式和時機。
組合機制,即將一個類的對象嵌入另一個對象中,由另一個對象來決定是否調用嵌入對象的行為以便擴展自己的行為,我們稱這個嵌入的對象為裝飾器(Decorator)
顯然,為了擴展對象功能頻繁修改父類或者派生子類這種方式并不可取。在面向對象的設計中,我們應該盡量使用對象組合,而不是對象繼承來擴展和復用功能。裝飾器模式就是基于對象組合的方式,可以很靈活的給對象添加所需要的功能。裝飾器模式的本質就是動態(tài)組合。動態(tài)是手段,組合才是目的。總之,裝飾模式是通過把復雜的功能簡單化,分散化,然后在運行期間,根據需要來動態(tài)組合的這樣一個模式。
裝飾模式定義裝飾模式(Decorator Pattern) :動態(tài)地給一個對象增加一些額外的職責(Responsibility),就增加對象功能來說,裝飾模式比生成子類實現更為靈活。其別名也可以稱為包裝器(Wrapper),與適配器模式的別名相同,但它們適用于不同的場合。根據翻譯的不同,裝飾模式也有人稱之為“油漆工模式”,它是一種對象結構型模式。
裝飾模式的優(yōu)點裝飾模式與繼承關系的目的都是要擴展對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。
可以通過一種動態(tài)的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的裝飾器,從而實現不同的行為。
通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創(chuàng)造出很多不同行為的組合??梢允褂枚鄠€具體裝飾類來裝飾同一對象,得到功能更為強大的對象。
模式結構和說明聚合關系用一條帶空心菱形箭頭的直線表示,上圖表示Component聚合到Decorator上,或者說Decorator由Component組成。
繼承關系用一條帶空心箭頭的直接表示
看懂UML類圖請看這個文檔
Component:組件對象的接口,可以給這些對象動態(tài)的添加職責;
ConcreteComponent:具體的組件對象,實現了組件接口。該對象通常就是被裝飾器裝飾的原始對象,可以給這個對象添加職責;
Decorator:所有裝飾器的父類,需要定義一個與Component接口一致的接口(主要是為了實現裝飾器功能的復用,即具體的裝飾器A可以裝飾另外一個具體的裝飾器B,因為裝飾器類也是一個Component),并持有一個Component對象,該對象其實就是被裝飾的對象。如果不繼承Component接口類,則只能為某個組件添加單一的功能,即裝飾器對象不能再裝飾其他的裝飾器對象。
ConcreteDecorator:具體的裝飾器類,實現具體要向被裝飾對象添加的功能。用來裝飾具體的組件對象或者另外一個具體的裝飾器對象。
裝飾器的示例代碼1.Component抽象類, 可以給這些對象動態(tài)的添加職責
abstract class Component { abstract public function operation(); }
2.Component的實現類
class ConcreteComponent extends Component { public function operation() { echo __CLASS__ . "|" . __METHOD__ . " "; } }
3.裝飾器的抽象類,維持一個指向組件對象的接口對象,?并定義一個與組件接口一致的接口
abstract class Decorator extends Component { /** * 持有Component的對象 */ protected $component; /** * 構造方法傳入 */ public function __construct(Component $component) { $this->component = $component; } abstract public function operation(); }
4.裝飾器的具體實現類,向組件對象添加職責,beforeOperation(),afterOperation()為前后添加的職責。
class ConcreteDecoratorA extends Decorator { //在調用父類的operation方法的前置操作 public function beforeOperation() { echo __CLASS__ . "|" . __METHOD__ . " "; } //在調用父類的operation方法的后置操作 public function afterOperation() { echo __CLASS__ . "|" . __METHOD__ . " "; } public function operation() { $this->beforeOperation(); $this->component->operation();//這里可以選擇性的調用父類的方法,如果不調用則相當于完全改寫了方法,實現了新的功能 $this->afterOperation(); } } class ConcreteDecoratorB extends Decorator { //在調用父類的operation方法的前置操作 public function beforeOperation() { echo __CLASS__ . "|" . __METHOD__ . " "; } //在調用父類的operation方法的后置操作 public function afterOperation() { echo __CLASS__ . "|" . __METHOD__ . " "; } public function operation() { $this->beforeOperation(); $this->component->operation();//這里可以選擇性的調用父類的方法,如果不調用則相當于完全改寫了方法,實現了新的功能 $this->afterOperation(); } }
5.客戶端使用裝飾器
class Client { public function main() { $component = new ConcreteComponent(); $decoratorA = new ConcreteDecoratorA($component); $decoratorB = new ConcreteDecoratorB($decoratorA); $decoratorB->operation(); } } $client = new Client(); $client->main();
6.運行結果
oncreteDecoratorB|ConcreteDecoratorB::beforeOperation ConcreteDecoratorA|ConcreteDecoratorA::beforeOperation ConcreteComponent|ConcreteComponent::operation ConcreteDecoratorA|ConcreteDecoratorA::afterOperation ConcreteDecoratorB|ConcreteDecoratorB::afterOperation裝飾模式需要注意的問題
一個裝飾類的接口必須與被裝飾類的接口保持相同,對于客戶端來說無論是裝飾之前的對象還是裝飾之后的對象都可以一致對待。
盡量保持具體組件類ConcreteComponent的輕量,不要把主邏輯之外的輔助邏輯和狀態(tài)放在具體組件類中,可以通過裝飾類對其進行擴展。 如果只有一個具體組件類而沒有抽象組件類,那么抽象裝飾類可以作為具體組件類的直接子類。
適用環(huán)境需要在不影響組件對象的情況下,以動態(tài)、透明的方式給對象添加職責。
當不能采用繼承的方式對系統(tǒng)進行擴充或者采用繼承不利于系統(tǒng)擴展和維護時可以考慮使用裝飾類。
本文已經收錄在系列文章Laravel源碼學習里,歡迎訪問閱讀。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/28699.html
摘要:定義裝飾模式力圖解決的問題是過度使用了繼承來擴展對象的功能。裝飾模式是類繼承的另外一種選擇,類繼承在編譯時候增加行為,而裝飾模式是在運行時增加行為。 The Decorator Pattern is a design pattern that allows behavior to be added to an individual object, either staticall...
摘要:然后在創(chuàng)建一個抽象的類,該類也實現了接口,并且持有一個類的對象。第四步創(chuàng)建具體的裝飾器類,該類繼承了類。第五步使用裝飾對象。 原文鏈接譯者:smallclover個人翻譯,因為英語水平的原因可能會詞不達意,十分歡迎各位讀者指出其中的錯誤,希望能對讀者有1%的用處,謝謝! 設計模式-裝飾器模式 裝飾器模式允許使用者將新功能添加到現有的對象而不需要改變它的數據結構。這種類型的設計模式來源于...
摘要:裝飾對象包含一個真實對象的引用裝飾對象接受所有來自客戶端的請求。裝飾對象可以在轉發(fā)這些請求以前或以后增加一些附加功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。 Decorator Pattern 裝飾者模式 綱要: 1. 一個初學者的疑惑 2. 裝飾者模式的特點 3. 簡單case掌握裝飾者模式 4. laravel中裝飾者模式的應用 Con...
摘要:把和拼接在一起的場所是,所以需要造一個類,在其內部實現對的操作中實現了把原有的進過個的裝飾后得到的新的,新的還是的實現,還是原來的物種。 說明:Laravel中Middleware的實現主要利用了Decorator Pattern的設計,本文主要先學習下Decorator Pattern如何實現,為后面學習Middleware的設計做個鋪墊。Decorator Pattern和Adap...
摘要:相關設計模式裝飾者模式和代理模式裝飾者模式關注再一個對象上動態(tài)添加方法代理模式關注再對代理對象的控制訪問,可以對客戶隱藏被代理類的信息裝飾著模式和適配器模式都叫包裝模式關于新職責適配器也可以在轉換時增加新的職責,但主要目的不在此。 0x01.定義與類型 定義:裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態(tài)地擴展一個對象的功能。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實的...
閱讀 3522·2023-04-25 23:25
閱讀 2193·2021-11-12 10:36
閱讀 2869·2019-08-30 12:47
閱讀 2128·2019-08-29 18:45
閱讀 518·2019-08-29 17:28
閱讀 1858·2019-08-29 17:15
閱讀 1776·2019-08-29 16:05
閱讀 1501·2019-08-29 14:17