摘要:什么是裝飾者模式今天我們來講另外一個(gè)非常實(shí)用的設(shè)計(jì)模式裝飾者模式。就增加功能來說,裝飾者模式相比生成子類更為靈活。下面,裝飾者模式就要正式登場了。下一步,我們可以愉快的去使用裝飾者模式啦
什么是裝飾者模式
今天我們來講另外一個(gè)非常實(shí)用的設(shè)計(jì)模式:裝飾者模式。這個(gè)名字聽上去有些莫名其妙,不著急,我們先來記住它的一個(gè)別名:包裝器模式。
我們記著這兩個(gè)名字來開始今天的文章。
首先還是上《設(shè)計(jì)模式》一書中的經(jīng)典定義:
動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。
就增加功能來說,裝飾者模式相比生成子類更為靈活。
我們來分析一下這個(gè)定義。
給對(duì)象添加一些新的職責(zé),我們很容易想到創(chuàng)建子類來繼承父類,然后在子類上增加額外的職責(zé)。
那什么是動(dòng)態(tài)地呢?應(yīng)該就是說這些新添加的職責(zé)在類一開始創(chuàng)建的時(shí)候我們并不知道,而是在使用過程根據(jù)需要而添加的。
相比生成子類更為靈活,這句話讓裝飾者模式和子類繼承赤裸裸的刀兵相見了。沒有對(duì)比就沒有傷害,那我們就用例子來驗(yàn)證這句話。
傳統(tǒng)面向?qū)ο蟮膶?shí)現(xiàn)我們假設(shè)你是以為已經(jīng)走上人生巔峰的汽車生產(chǎn)商,你的公司生產(chǎn)各種用途的汽車,某一天一個(gè)客戶下單了四種汽車,分別是家用轎車、SUV、旅行車和跑車。我們很輕松地像下面這樣進(jìn)行交付了。
var Car = function(){} Car.prototype.start = function(){ console.log("轟轟轟,啟動(dòng)正常!") } var Sedan = new car();// 小轎車 var Suv = new Car();// SUV var Wagon=new Car();// 旅行車 var Roadster=new Car();// 跑車 //是不是又學(xué)會(huì)了幾個(gè)英文單詞?
過了幾天客戶找來了,說最近人們愛上了西藏自駕游,人們都希望能夠選裝一些方便越野和載物的功能,比如加裝雪地胎、行李箱,升高底盤。
有經(jīng)驗(yàn)的你滿口答應(yīng)下來,這個(gè)簡單,于是你交付了下面的代碼:
//SUV Suv.prototype.changeTire = function(){ console.log("我換了雪地胎"); } Suv.prototype.addHeight = function(){ console.log("我升高了底盤"); } Suv.prototype.addBox = function(){ console.log("我安裝了行李箱"); } //Wagon Wagon.prototype.changeTire = function(){ console.log("我換了雪地胎"); } Wagon.prototype.addHeight = function(){ console.log("我升高了底盤"); } Wagon.prototype.addBox = function(){ console.log("我安裝了行李箱"); } //Sedan Sedan.prototype.changeTire = function(){ console.log("我換了雪地胎"); } Sedan.prototype.addHeight = function(){ console.log("我升高了底盤"); } Sedan.prototype.addBox = function(){ console.log("我安裝了行李箱"); } // 使用 var suv = new Suv(); suv.changeTire(); suv.addHeight(); suv.addBox(); suv.start(); ...
你增加了多少種特性?3x3=9種。
你又問,我直接把這三個(gè)特性加在Car上不行嗎?就不用這么麻煩了。
當(dāng)然不行,因?yàn)槲覀冞€有一種車:Roadster跑車。
你能想象法拉利換了雪地胎背上行李箱升高底盤是個(gè)什么死樣子嗎?這么干的人肯定瘋了。
如果我們把特性一股腦加在Car上,就避免不了這種情況的發(fā)生。
這個(gè)時(shí)候,就體現(xiàn)出子類繼承的不靈活之處。
下面,裝飾者模式就要正式登場了。
var Car=function (){} Car.prototype.start=function(){ console.log("轟轟轟,啟動(dòng)正常!") } // 創(chuàng)建裝飾類(包裝類) var ChangeTireDec=function(car){ this.car=car; } var AddHeightDec=function(car){ this.car=car; } var AddBoxDec=function(car){ this.car=car; } // 裝飾類具有和Car同樣的特性,只不過額外執(zhí)行了一些其他的操作 ChangeTireDec.prototype.start=function(){ console.log("我換了雪地胎"); this.car.start(); } AddHeightDec.prototype.start=function(car){ console.log("我升高了底盤"); this.car.start(); } AddBoxDec.prototype.start=function(car){ console.log("我安裝了行李箱"); this.car.start(); } // 使用 var suv=new Suv(); suv=new ChangeTireDec(suv); suv=new AddHeightDec(suv); suv=new AddBoxDec(suv); suv.start();
上面的代碼你增加了幾種特性?只有三種!而且不管你是給SUV還是Wagon還是Sedan加裝,都不需要再增加特性的代碼。
這,就是裝飾者模式的優(yōu)勢(shì)所在。
現(xiàn)在我們?cè)倩剡^頭來看看GoF的定義:
動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。
就增加功能來說,裝飾者模式相比生成子類更為靈活。
怎么樣,是不是如同1+1=2一樣簡單了?現(xiàn)在你應(yīng)該也明白了為什么裝飾者模式又叫座包裝器模式了。因?yàn)樗鼘㈩惖脑刑匦园b起來,添加其他的特性,就像一個(gè)箱子一樣。而且實(shí)現(xiàn)過程中,還滿足了封閉-開放原則。
JavaScript的實(shí)現(xiàn)上面的例子中,我們是模擬了傳統(tǒng)的面向?qū)ο笳Z言來解釋什么是裝飾者模式。我們都知道,要?jiǎng)討B(tài)改變JavaScript對(duì)象非常容易,可以向操作變量一個(gè)操作對(duì)象,我們?cè)賮砀膶懴律厦娴睦?,讓它?b>javasripty
var car = { start: function(){ console.log("轟轟轟,正常啟動(dòng)!"); } } var ChangeTireDec = function(){ console.log("我換了雪地胎"); } var AddHeightDec = function(){ console.log("我升高了底盤"); } var AddBoxDec = function(){ console.log("我安裝了行李箱"); } var start1 = car.start; car.start=function(){ ChangeTireDec(); start1(); } var start2=car.start; car.start = function(){ AddHeightDec(); start2(); } var start3=car.start(); car.start = function(){ AddBoxDec(); start3(); } // 執(zhí)行 car.start();實(shí)際中的應(yīng)用
從上面的例子我們可以看出來,我們不斷的將car.start的引用賦值給臨時(shí)變量,然后將原來的car.start指向新的對(duì)象--包含了原來對(duì)象的引用和新的特性的對(duì)象。這很好的保證了代碼的開放-封閉原則,這是今天第二次提到這個(gè)原則了,就是對(duì)修改封閉,對(duì)新增開放。
特別當(dāng)你要重構(gòu)一個(gè)非常復(fù)雜的多人項(xiàng)目時(shí),如果你不想因?yàn)樾薷牧送碌囊恍写a而引起“蝴蝶效應(yīng)”,那么將他的方法整個(gè)打包賦值然后用裝飾者模式增加新的功能,是一種非常安全而且高效的做法。
下一步,我們可以愉快的去使用裝飾者模式啦!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107792.html
摘要:做前端開發(fā)已經(jīng)好幾年了,對(duì)設(shè)計(jì)模式一直沒有深入學(xué)習(xí)總結(jié)過。今天第一天,首先來講策略模式。什么是策略模式四兄弟的經(jīng)典設(shè)計(jì)模式中,對(duì)策略模式的定義如下定義一系列的算法,把它們一個(gè)個(gè)封裝起來,并且使它們可互相替換。 做前端開發(fā)已經(jīng)好幾年了,對(duì)設(shè)計(jì)模式一直沒有深入學(xué)習(xí)總結(jié)過。隨著架構(gòu)相關(guān)的工作越來越多,越來越能感覺到設(shè)計(jì)模式成為了我前進(jìn)道路上的一個(gè)阻礙。所以從今天開始深入學(xué)習(xí)和總結(jié)經(jīng)典的設(shè)計(jì)模...
摘要:另外,適配器模式和其它幾個(gè)模式可能容易讓人迷惑,這里說一下大概的區(qū)別適配器和橋接模式雖然類似,但橋接的出發(fā)點(diǎn)不同,橋接的目的是將接口部分和實(shí)現(xiàn)部分分離,從而對(duì)他們可以更為容易也相對(duì)獨(dú)立的加以改變。 1. 簡介 適配器模式(Adapter)是將一個(gè)類(對(duì)象)的接口(方法或?qū)傩裕┺D(zhuǎn)化成客戶希望的另外一個(gè)接口(方法或?qū)傩裕?,適配器模式使得原本由于接口不兼容而不能一起工作的那些類(對(duì)象)可以一...
摘要:測(cè)試類設(shè)計(jì)模式裝飾者模式工廠模式只能讀啦會(huì)報(bào)錯(cuò)只讀異常可以正確運(yùn)行第二部分定義抽象組件是具體組件和抽象裝飾類的共同父類,聲明了在具體組件中實(shí)現(xiàn)的方法。 前言 本篇文章分為四個(gè)部分:第一部分會(huì)舉一個(gè)例子引出裝飾者模式,讓讀者對(duì)裝飾者模式有個(gè)感官上的認(rèn)識(shí);第二部分會(huì)給出裝飾者模式的定義(當(dāng)然我們主要不是來背定義,就當(dāng)做積累專業(yè)名詞來記吧,我個(gè)人是很不喜歡下定義的);第三部分,我會(huì)拿jdk中...
摘要:作者按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用和兩種語言實(shí)現(xiàn)。誠然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊(cè)只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式原文地址是每天一個(gè)設(shè)計(jì)模式之裝飾者模式歡迎關(guān)注個(gè)人技術(shù)博客。 作者按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript和python兩種語言實(shí)現(xiàn)。誠然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊(cè)只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式...
摘要:作者按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用和兩種語言實(shí)現(xiàn)。誠然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊(cè)只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式原文地址是每天一個(gè)設(shè)計(jì)模式之裝飾者模式歡迎關(guān)注個(gè)人技術(shù)博客。 作者按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript和python兩種語言實(shí)現(xiàn)。誠然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊(cè)只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式...
閱讀 2978·2021-11-25 09:43
閱讀 3600·2021-11-24 11:13
閱讀 3373·2021-10-14 09:42
閱讀 2578·2021-09-23 11:53
閱讀 3622·2021-09-22 15:57
閱讀 3233·2021-09-02 09:54
閱讀 3510·2019-08-30 13:47
閱讀 1650·2019-08-29 16:55