摘要:當(dāng)接口比較多,裝飾器也比較多時(shí),可以獨(dú)立抽取一個(gè)裝飾器父類,實(shí)現(xiàn)目標(biāo)類的所有接口,再創(chuàng)建真正的裝飾器來繼承這個(gè)父類。四的實(shí)現(xiàn)方式提供了一種類似的注解的語法糖,來實(shí)現(xiàn)裝飾者模式。
歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:
所謂裝飾者模式,就是動(dòng)態(tài)的給類或?qū)ο笤黾勇氊?zé)的設(shè)計(jì)模式。它能在不改變類或?qū)ο笞陨淼幕A(chǔ)上,在程序的運(yùn)行期間動(dòng)態(tài)的添加職責(zé)。這種設(shè)計(jì)模式非常符合敏捷開發(fā)的設(shè)計(jì)思想:先提煉出產(chǎn)品的MVP(Minimum Viable Product,最小可用產(chǎn)品),再通過快速迭代的方式添加功能。
二、傳統(tǒng)面向?qū)ο笳Z言的實(shí)現(xiàn)方式var Car = function() {} Car.prototype.drive = function() { console.log("乞丐版"); } var AutopilotDecorator = function(car) { this.car = car; } AutopilotDecorator.prototype.drive = function() { this.car.drive(); console.log("啟動(dòng)自動(dòng)駕駛模式"); } var car = new Car(); car = new AutopilotDecorator(car); car.drive(); //乞丐版;啟動(dòng)自動(dòng)駕駛模式;
這種方式的實(shí)現(xiàn)要點(diǎn)是裝飾器類要維護(hù)目標(biāo)對象的一個(gè)引用,同時(shí)要實(shí)現(xiàn)目標(biāo)類的所有接口(這個(gè)例子里的drive方法,如果還有其它方法,比如brake,AutopilotDecorator也要實(shí)現(xiàn))。調(diào)用方法時(shí),先執(zhí)行目標(biāo)對象原有的方法,再執(zhí)行自行添加的特性。
當(dāng)接口比較多,裝飾器也比較多時(shí),可以獨(dú)立抽取一個(gè)裝飾器父類,實(shí)現(xiàn)目標(biāo)類的所有接口,再創(chuàng)建真正的裝飾器來繼承這個(gè)父類。
var Car = function() {} Car.prototype.drive = function() { console.log("乞丐版"); } /* 多了一個(gè)剎車方法 */ Car.prototype.brake = function() { console.log("剎車"); } /* 實(shí)現(xiàn)所有接口的裝飾器父類 */ var CarDecorator = function(car) { this.car = car; } CarDecorator.prototype = { drive: function() { this.car.drive(); }, brake: function() { this.car.brake(); } } /* 真正的裝飾器 */ var AutopilotDecorator = function(car) { CarDecorator.call(this, car); } AutopilotDecorator.prototype = new CarDecorator(); AutopilotDecorator.prototype.drive = function() { this.car.drive(); console.log("啟動(dòng)自動(dòng)駕駛模式"); } /* 真正的裝飾器 */ var HybridDecorator = function(car) { CarDecorator.call(this, car); } HybridDecorator.prototype = new CarDecorator(); HybridDecorator.prototype.brake = function() { this.car.brake(); console.log("啟動(dòng)充電模式"); } var car = new Car(); car = new AutopilotDecorator(car); car = new HybridDecorator(car); car.drive(); //乞丐版;啟動(dòng)自動(dòng)駕駛模式; car.brake(); //剎車;啟動(dòng)充電模式;三、JS基于對象的實(shí)現(xiàn)方式
var car = { drive: function() { console.log("乞丐版"); } } var driveBasic = car.drive; var autopilotDecorator = function() { console.log("啟動(dòng)自動(dòng)駕駛模式"); } var carToDecorate = Object.create(car); carToDecorate.drive = function() { driveBasic(); autopilotDecorator(); } carToDecorate.drive(); //乞丐版;啟動(dòng)自動(dòng)駕駛模式;
這種實(shí)現(xiàn)方式完全是基于JS自身的語言特點(diǎn)做考量。定義類的目的是實(shí)現(xiàn)代碼的封裝和復(fù)用,而JS這門語言是沒有類的概念的。它只有2種數(shù)據(jù)類型:基本類型和對象類型。實(shí)現(xiàn)邏輯的封裝和代碼的重用只需要通過對象來組織代碼,然后利用原生提供的克隆機(jī)制(Object.create)來達(dá)到目的。
從代碼的角度看,如果想擴(kuò)展drive方法,只需要用一個(gè)變量來保存原函數(shù)的引用,然后再重寫drive方法就可以了。在重寫的方法里面,只要記得調(diào)用方法原有的行為就行。
另外,我們可以通過以下的工具函數(shù),達(dá)到裝飾函數(shù)的目的:
Function.prototype.after = function(afterfn) { var _self = this; return function() { var ret = _self.apply(this, arguments); afterfn.apply(this, arguments); return ret; } } var car = { drive: function() { console.log("乞丐版"); } } var autopilotDecorator = function() { console.log("啟動(dòng)自動(dòng)駕駛模式"); } var carToDecorate = Object.create(car); carToDecorate.drive = car.drive.after(autopilotDecorator); carToDecorate.drive(); //乞丐版;啟動(dòng)自動(dòng)駕駛模式;
通過在Function的原型鏈上定義after函數(shù),給所有的函數(shù)都賦予了被擴(kuò)展的功能,當(dāng)然也可以根據(jù)需要定義一個(gè)before的函數(shù),在函數(shù)執(zhí)行前去做一些操作。這種實(shí)現(xiàn)方式借鑒了AOP(Aspect Oriented Programming,面向切面編程)的思想。
四、ES7的實(shí)現(xiàn)方式ES7提供了一種類似的Java注解的語法糖decorator,來實(shí)現(xiàn)裝飾者模式。使用起來非常簡潔:
function autopilotDecorator(target, key, descriptor) { const method = descriptor.value; descriptor.value = () => { method.apply(target); console.log("啟動(dòng)自動(dòng)駕駛模式"); } return descriptor; } class Car { @autopilotDecorator drive() { console.log("乞丐版"); } } let car = new Car(); car.drive(); //乞丐版;啟動(dòng)自動(dòng)駕駛模式;
decorator的實(shí)現(xiàn)依賴于ES5的Object.defineProperty方法。defineProperty所做的事情是為一個(gè)對象增加新的屬性,或者更改某個(gè)已存在的屬性。調(diào)用方式是Object.defineProperty(obj, prop, descriptor)。
var o = {}; // 創(chuàng)建一個(gè)新對象 // 在對象中添加一個(gè)屬性 Object.defineProperty(o, "name", { value : "Dickens", writable : true, enumerable : true, configurable : true }); // 在對象中添加一個(gè)方法 Object.defineProperty(o, "sayHello", { value : function() { console.log("Hello, my name is: ", this.name) }, writable : true, enumerable : true, configurable : true }); o.sayHello() //Hello, my name is: Dickens
decorator的參數(shù)跟defineProperty是完全一樣的,含義也類似,通過修改descripter,就能達(dá)到擴(kuò)展功能的目的。
五、總結(jié)本文介紹了裝飾者模式的基本概念,并通過不同的實(shí)現(xiàn)方式來介紹使用方法。對于不同的使用方法,也作了比較透徹的解釋,讓大家不但知其然,還知其所以然。
裝飾者模式是一種十分常用且功能強(qiáng)大的模式,利用ES7的語法糖,我們能用非常簡潔的方式來表達(dá)裝飾的意圖,推薦大家在實(shí)際項(xiàng)目中用起來。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93344.html
摘要:裝飾者模式裝飾者模式就是動(dòng)態(tài)的給類或?qū)ο笤黾庸δ艿脑O(shè)計(jì)模式。下的實(shí)現(xiàn)里的裝飾器目前處在建議征集的第二階段,不被瀏覽器所支持,如果想要提前使用這個(gè)新特性就需要,等工具進(jìn)行轉(zhuǎn)譯。這里介紹下的用法。 1.1、裝飾者模式 裝飾者模式就是動(dòng)態(tài)的給類或?qū)ο笤黾庸δ艿脑O(shè)計(jì)模式。在程序運(yùn)行時(shí)動(dòng)態(tài)的給一個(gè)具備基礎(chǔ)功能的類或?qū)ο筇砑有碌墓δ?,并且不?huì)改變會(huì)破壞基礎(chǔ)類和對象的功能。先提煉出產(chǎn)品的最小可用產(chǎn)品...
摘要:設(shè)計(jì)模式裝飾者模式何為裝飾者,意思就是,在不影響對象主功能的情況下,再添加一些額外的功能,使對象具備更多的功能。與繼承相比,裝飾者是一種更靈活輕便的做法。 javascript設(shè)計(jì)模式 --- 裝飾者模式 何為裝飾者,意思就是,在不影響對象主功能的情況下,再添加一些額外的功能,使對象具備更多的功能。與繼承相比,裝飾者是一種更靈活輕便的做法。下面我們看看javascript里裝飾者模式 ...
摘要:但是,這樣做的后果就是,我們會(huì)不斷的改變本體,就像把鳳姐送去做整形手術(shù)一樣。在中,我們叫做引用裝飾。所以,這里引入的裝飾模式裝飾親切,熟悉,完美。實(shí)例講解裝飾上面那個(gè)例子,只能算是裝飾模式的一個(gè)不起眼的角落。 裝飾者,英文名叫decorator. 所謂的裝飾,從字面可以很容易的理解出,就是給 土肥圓,化個(gè)妝,華麗的轉(zhuǎn)身為白富美,但本體還是土肥圓。 說人話.咳咳~ 在js里面一切都是對...
摘要:自行車的基類如下其它方法那么我們可以先創(chuàng)建一個(gè)裝飾者模式基類這個(gè)基類其實(shí)沒有做什么事情,它只是接受一個(gè)實(shí)例,實(shí)現(xiàn)其對應(yīng)的方法,并且將調(diào)用其方法返回而已。 showImg(https://segmentfault.com/img/bVbs3pt?w=650&h=651); 什么是裝飾者模式 裝飾者模式是一種為函數(shù)或類增添特性的技術(shù),它可以讓我們在不修改原來對象的基礎(chǔ)上,為其增添新的能力和...
摘要:裝飾者要實(shí)現(xiàn)這些相同的方法繼承自裝飾器對象創(chuàng)建具體的裝飾器,也是接收作對參數(shù)接下來我們要為每一個(gè)功能創(chuàng)建一個(gè)裝飾者對象,重寫父級(jí)方法,添加我們想要的功能。 裝飾模式 僅僅包裝現(xiàn)有的模塊,使之 更加華麗 ,并不會(huì)影響原有接口的功能 —— 好比你給手機(jī)添加一個(gè)外殼罷了,并不影響手機(jī)原有的通話、充電等功能; 使用 ES7 的 decorator ES7 中增加了一個(gè) decorator 屬性...
閱讀 792·2021-11-22 13:52
閱讀 1594·2021-09-27 13:36
閱讀 2912·2021-09-24 09:47
閱讀 2295·2021-09-22 15:48
閱讀 3657·2021-09-22 15:39
閱讀 1528·2019-08-30 12:43
閱讀 2980·2019-08-29 18:39
閱讀 3266·2019-08-29 12:51