摘要:裝飾器模式允許向一個(gè)現(xiàn)有的對象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這便是裝飾模式,通過一層一層的裝飾,我們可以靈活的得到我們想要的結(jié)果。可以輕松的添加新的裝飾器類或者新的組件來創(chuàng)建靈活的結(jié)構(gòu)。
前言
在編碼的時(shí)候,我們?yōu)榱藬U(kuò)展一個(gè)類經(jīng)常是使用繼承方式來實(shí)現(xiàn),隨著擴(kuò)展功能的增多,子類會越來越膨脹,使系統(tǒng)變得不靈活。
裝飾器模式( Decorator Pattern )允許向一個(gè)現(xiàn)有的對象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。它能讓我們在擴(kuò)展類的時(shí)候讓系統(tǒng)較好的保持靈活性。
那么裝飾器模式具體是什么樣的呢?
從一個(gè)情景開始我們有一塊地,在這塊地上,我們要蓋一棟有好幾間房間的別墅,每間房間的裝修費(fèi)用都不同,現(xiàn)在,我們要對蓋別墅的費(fèi)用進(jìn)行計(jì)算。
先定義一個(gè)Land類,表示這塊地,Land類定義了在這塊地上蓋別墅需要花錢這個(gè)規(guī)則。
abstract class Land { abstract public function cost(); }
Land已經(jīng)定義好了在這塊地上蓋房需要花錢的這個(gè)規(guī)則了,但是蓋一間房間具體花多少錢呢?
此時(shí)我們再定義一個(gè)Room類,這個(gè)類具體的定義了一個(gè)房間建造的基本費(fèi)用(一個(gè)最簡單房間,里面啥也沒有的)。
class Room extends Land { private $money = 1000; public function cost() { return $this->money; } }
然后開始建造房間,我們建了兩個(gè)房間,分別是客廳和餐廳,用LivingRoom類和DiningRoom類來表示
class LivingRoom extends Room { public function cost() { return parent::cost()+200; //客廳的建造費(fèi)用在房屋建造費(fèi)用的基礎(chǔ)上多200,比如要買沙發(fā),電視 } } class DiningRoom extends Room { public function cost() { return parent::cost()+100; //餐廳的建造費(fèi)用在房屋建造費(fèi)用的基礎(chǔ)上多100,比如買餐桌 } }
現(xiàn)在,我們很容易就能得到建造一間客廳所需的花費(fèi)
$livingRoomCost = new LivingRoom(); echo $livingRoomCost->cost();問題的產(chǎn)生
不過,這樣的結(jié)構(gòu)并不具備靈活性,雖然我們可以很容易的分別得出建造一間客廳和建造一間餐廳的費(fèi)用,但是,如果我買的地比較小,只能把餐廳和客廳建在同一個(gè)房間里,那要怎么去計(jì)算費(fèi)用?難道還要很麻煩的去創(chuàng)建一個(gè)包含客廳和餐廳的LivingDiningRoom類?這樣做的話除了麻煩,還會使代碼產(chǎn)生重復(fù)。
解決問題為了更好的解決這個(gè)問題,我們得做一些調(diào)整,同樣先聲明Land類和Room類,不同的是,引入了一個(gè)房間的裝飾類RoomDecorator,它繼承了Land類,因?yàn)闆]有實(shí)現(xiàn)Land類的cost()方法,所以需將它聲明為抽象類,并且定義了一個(gè)以Land類的對象為參數(shù)的構(gòu)造方法,傳入的對象會保存在$land屬性中,該屬性聲明為protected,以便子類訪問。具體如下。
abstract class RoomDecorator extends Land { protected $land; public function __construct(Land $land) { $this->land = $land; } }
然后我們再重新定義客廳類和餐廳類
class LivingRoom extends RoomDecorator { public function cost() { return $this->land->cost()+200; } } class DiningRoom extends RoomDecorator { public function cost() { return $this->land->cost()+100; } }
這兩個(gè)類都擴(kuò)展自RoomDecorator類,這意味著它們都擁有指向Land對象的引用。當(dāng)它們的cost()方法被調(diào)用時(shí),都會先調(diào)用所引用的Land類對象的cost()方法,然后再執(zhí)行自己特有的操作。
所以這時(shí)候,建造一間客廳所需的費(fèi)用是這樣計(jì)算
$livingRoomCost = new LivingRoom(new Room()); echo $livingRoomCost->cost(); //輸出1200
建造一間餐廳所需的費(fèi)用是這樣計(jì)算
$diningRoomCost = new DiningRoom(new Room()); echo $diningRoomCost->cost(); //輸出1100
回到剛才的問題,如果我們需計(jì)算建造一間包含客廳餐廳的房間所需費(fèi)用,代碼如下
$livingRoom = new DiningRoom(new LivingRoom(new Room())); echo $livingRoom->cost(); //輸出1300
看,我們現(xiàn)在計(jì)算建造費(fèi)用的思路是:計(jì)算出基礎(chǔ)房間的費(fèi)用 --> 在基礎(chǔ)房間上裝飾成客廳的費(fèi)用 --> 在客廳的基礎(chǔ)上加裝飾餐廳的費(fèi)用 --> 得到包含客廳餐廳的房間費(fèi)用。已經(jīng)不需要麻煩的通過創(chuàng)建一個(gè)LivingDiningRoom類來計(jì)算包含客廳餐廳的房間建造費(fèi)用了。
這便是裝飾模式,通過一層一層的裝飾,我們可以靈活的得到我們想要的結(jié)果。可以輕松的添加新的裝飾器類或者新的組件來創(chuàng)建靈活的結(jié)構(gòu)。
完整代碼money; } } //裝飾器 abstract class RoomDecorator extends Land { protected $land; public function __construct(Land $land) { $this->land = $land; } } class LivingRoom extends RoomDecorator { public function cost() { return $this->land->cost()+200; } } class DiningRoom extends RoomDecorator { public function cost() { return $this->land->cost()+100; } } $livingRoomCost = new LivingRoom(new Room()); echo $livingRoomCost->cost(); //輸出1200 $diningRoomCost = new DiningRoom(new Room()); echo $diningRoomCost->cost(); //輸出1100 $livingDining = new DiningRoom(new LivingRoom(new Room())); echo $livingDining->cost(); //輸出1300
the end.
happy coding! ^_^
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/25853.html
摘要:面向?qū)ο笤O(shè)計(jì)模式通常以類別或?qū)ο髞砻枋銎渲械年P(guān)系和相互作用,但不涉及用來完成應(yīng)用程序的特定類別或?qū)ο蟆@锸洗鷵Q原則里氏代換原則是面向?qū)ο笤O(shè)計(jì)的基本原則之一。 通俗易懂的設(shè)計(jì)模式 零、使用 1、安裝 2、測試 一、什么是設(shè)計(jì)模式 二、設(shè)計(jì)模式的類型 三、設(shè)計(jì)模式的六大原則 四、UML類圖 1、看懂UML類圖 2、解釋 五、資料 前言:花了一些時(shí)間再次熟悉了一遍...
摘要:三的洋蔥模型這里簡單講講在中是如何分層的,也就是說請求到達(dá)服務(wù)端后如何層層處理,直到響應(yīng)請求并將結(jié)果返回客戶端。從而使得端支持跨域等。 ??最近已經(jīng)使用過一段時(shí)間的nestjs,讓人寫著有一種java spring的感覺,nestjs可以使用express的所有中間件,此外完美的支持typescript,與數(shù)據(jù)庫關(guān)系映射typeorm配合使用可以快速的編寫一個(gè)接口網(wǎng)關(guān)。本文會介紹一下作...
摘要:三的洋蔥模型這里簡單講講在中是如何分層的,也就是說請求到達(dá)服務(wù)端后如何層層處理,直到響應(yīng)請求并將結(jié)果返回客戶端。從而使得端支持跨域等。 ??最近已經(jīng)使用過一段時(shí)間的nestjs,讓人寫著有一種java spring的感覺,nestjs可以使用express的所有中間件,此外完美的支持typescript,與數(shù)據(jù)庫關(guān)系映射typeorm配合使用可以快速的編寫一個(gè)接口網(wǎng)關(guān)。本文會介紹一下作...
摘要:如果看不懂的話,可以在評論區(qū)中提問,我會第一時(shí)間回答你無論何時(shí)我一直都在嗯哼該文章屬于編程中的那些經(jīng)典套路設(shè)計(jì)模式匯總系列 在正式閱讀前,我先談?wù)勎覀冊撚檬裁醋藙莺托膽B(tài)學(xué)習(xí)設(shè)計(jì)模式: 如果你還沒有過多的編程經(jīng)驗(yàn)(泛指半年以下),我建議你把它當(dāng)做小說來看,能看懂多少是多少,因?yàn)榘肽暌韵陆?jīng)驗(yàn)的程序員用到設(shè)計(jì)模式的情況只會出現(xiàn)在面試上,至于實(shí)際工作中?相對來說這部分不會由你負(fù)責(zé)。 如果你已...
閱讀 3579·2021-09-24 09:48
閱讀 1105·2021-09-10 10:51
閱讀 3283·2019-08-30 13:03
閱讀 3331·2019-08-30 12:51
閱讀 1399·2019-08-30 11:22
閱讀 1074·2019-08-29 18:38
閱讀 2045·2019-08-29 16:41
閱讀 3216·2019-08-29 15:32