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