欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Javascript設(shè)計(jì)模式之裝飾者模式詳解篇

 更新時(shí)間:2017年01月17日 09:23:19   作者:敲代碼的怪蜀黍  
本文主要介紹了Javascript設(shè)計(jì)模式之裝飾者模式的相關(guān)知識(shí)。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧

一、前言:

裝飾者模式(Decorator Pattern):在不改變?cè)惡屠^承的情況下動(dòng)態(tài)擴(kuò)展對(duì)象功能,通過(guò)包裝一個(gè)對(duì)象來(lái)實(shí)現(xiàn)一個(gè)新的具有原對(duì)象相同接口的新的對(duì)象。

裝飾者模式的特點(diǎn):

1. 在不改變?cè)瓕?duì)象的原本結(jié)構(gòu)的情況下進(jìn)行功能添加。

2. 裝飾對(duì)象和原對(duì)象具有相同的接口,可以使客戶以與原對(duì)象相同的方式使用裝飾對(duì)象。

3. 裝飾對(duì)象中包含原對(duì)象的引用,即裝飾對(duì)象是真正的原對(duì)象經(jīng)過(guò)包裝后的對(duì)象。

二、Javascript裝飾者模式詳解:

描述:

裝飾者模式中,可以在運(yùn)行時(shí)動(dòng)態(tài)添加附加功能到對(duì)象中。當(dāng)處理靜態(tài)類時(shí),這可能是一個(gè)挑戰(zhàn)。在Javascript中,由于對(duì)象是可變的,因此,添加功能到對(duì)象中的過(guò)程本身并不是問(wèn)題。

裝飾者模式的一個(gè)比較方便的特征在于其預(yù)期行為的可定制和可配置特性??梢詮膬H具有一些基本功能的普通對(duì)象開(kāi)始,然后從可用裝飾資源池中選擇需要用于增強(qiáng)普通對(duì)象的哪些功能,并且按照順序進(jìn)行裝飾,尤其是當(dāng)裝飾順序很重要的時(shí)候。

實(shí)現(xiàn)裝飾者模式的其中一個(gè)方法是使得每個(gè)裝飾者成為一個(gè)對(duì)象,并且該對(duì)象包含了應(yīng)該被重載的方法。每個(gè)裝飾者實(shí)際上繼承了目前已經(jīng)被前一個(gè)裝飾者進(jìn)行增強(qiáng)后的對(duì)象。每個(gè)裝飾方法在“繼承的對(duì)象”上調(diào)用了同樣的方法并獲取其值,此外它還繼續(xù)執(zhí)行了一些操作。

先上實(shí)例1:

//需要裝飾的類(函數(shù))
function Macbook() {
 this.cost = function () {
  return 1000;
 };
} 
//計(jì)算商品的包裝費(fèi)
function PackagingFee(macbook) {
 this.cost = function () {
  return macbook.cost() + 75;
 };
}
//計(jì)算商品的運(yùn)費(fèi)
function Freight(macbook) {
 this.cost = function () {
  return macbook.cost() + 300;
 };
} 
//計(jì)算商品的保險(xiǎn)費(fèi)用
function Insurance(macbook) {
 this.cost = function () {
  return macbook.cost() + 250;
 };
}
// 用法
var myMacbook = new Insurance(new Freight(new PackagingFee(new Macbook())));
console.log(myMacbook.cost());//1625

我們簡(jiǎn)單的分析下上面的代碼,上面的代碼中,一共定義了四個(gè)函數(shù)(其中一個(gè)需要修飾的函數(shù),三個(gè)用于修飾的函數(shù))。

然后,聲明一個(gè)變量myMacbook指向new出來(lái)的Insurance對(duì)象,Insurance對(duì)象的形參指向new出來(lái)的Freight對(duì)象,F(xiàn)reight對(duì)象的形參指向new出來(lái)的PackagingFee對(duì)象,PackagingFee對(duì)象的形參指向new出來(lái)的Macbook對(duì)象。

接下來(lái),調(diào)用myMacbook的cost方法。從上面的分析,我們可以得出 myMacbook.cost()的值等于(Freight對(duì)象的cost方法+250),F(xiàn)reight對(duì)象的cost方法等于(PackagingFee對(duì)象的cost方法+300),PackagingFee對(duì)象的cost方法等于(Macbook對(duì)象的cost方法+75)。

所以最終的結(jié)果是:myMacbook.cost()的值 = 250 + (300 + (75 + 1000)) = 1625。

// 用法
var myMacbook = new Insurance(new Freight(new PackagingFee(new Macbook())));
console.log(myMacbook.cost());//1625 
//上面的代碼等價(jià)于下面拆分后的代碼,或許拆分后代碼你更能看出前后的邏輯性
var macbook = new Macbook();
var package = new PackagingFee(macbook);
var freight = new Freight(package);
var myMacbook = new Insurance(freight);
//當(dāng)然,如果你不想聲明這么多變量(macbook、package、freight),只用一個(gè)變量也是可以的
var macbook = new Macbook();
macbook = new PackagingFee(macbook);
macbook = new Freight(macbook);
var myMacbook = new Insurance(macbook);

再看看實(shí)例2:

function ConcreteClass() {
 this.performTask = function () {
  this.preTask();
  console.log('doing something');
  this.postTask();
 };
}
function AbstractDecorator(decorated) {
 this.performTask = function () {
  decorated.performTask();
 };
}
function ConcreteDecoratorClass(decorated) {
 this.base = AbstractDecorator;
 this.base(decorated);// add performTask method
 decorated.preTask = function () {
  console.log('pre-calling..');
 };
 decorated.postTask = function () {
  console.log('post-calling..');
 };
}
var concrete = new ConcreteClass();
var decorator1 = new ConcreteDecoratorClass(concrete);
decorator1.performTask();
//pre-calling..
//doing something
//post-calling..

實(shí)例2實(shí)際上和實(shí)例1是非常類似的,我們來(lái)簡(jiǎn)單分析下吧。首先,實(shí)例2中定義了三個(gè)函數(shù),然后聲明了兩個(gè)變量concrete和decorator1,最后調(diào)用了decorator1的performTask方法。

粗看一眼,ConcreteDecoratorClass里面好像并沒(méi)有performTask方法。我們先來(lái)分析下面的兩行代碼:

var concrete = new ConcreteClass(); //聲明一個(gè)變量concrete指向new出來(lái)的ConcreteClass對(duì)象
var decorator1 = new ConcreteDecoratorClass(concrete); //聲明一個(gè)變量decorator1指向new出來(lái)的ConcreteDecoratorClass對(duì)象,并傳入變量concrete作為形參

然后,我們?cè)賮?lái)逐行分析下ConcreteDecoratorClass函數(shù)里面的代碼:

this.base = AbstractDecorator; //定義一個(gè)當(dāng)前對(duì)象(decorator1)的base屬性,并指向函數(shù)AbstractDecorator
this.base(decorated); //調(diào)用base屬性指向的函數(shù),也就是調(diào)用AbstractDecorator函數(shù),同時(shí)傳入形參decorated,形參decorated指向new出來(lái)的ConcreteClass對(duì)象

說(shuō)到這里,好像還是沒(méi)有分析出ConcreteDecoratorClass函數(shù)里面有performTask方法,重點(diǎn)是看 "this"!

ConcreteDecoratorClass函數(shù)中的this指向new出來(lái)的ConcreteDecoratorClass對(duì)象(也就是和decorator1指向同一個(gè)對(duì)象);

AbstractDecorator函數(shù)里面的this關(guān)鍵是看哪個(gè)對(duì)象來(lái)調(diào)用這個(gè)函數(shù),this就指向哪個(gè)對(duì)象(從代碼 “this.base = AbstractDecorator; this.base(decorated);” 中我們可以看出是new出來(lái)的ConcreteDecoratorClass對(duì)象在調(diào)用AbstractDecorator函數(shù)),所以AbstractDecorator函數(shù)里面的this指向new出來(lái)的ConcreteDecoratorClass對(duì)象(也和decorator1指向同一個(gè)對(duì)象)。

總結(jié)下來(lái),我們會(huì)發(fā)現(xiàn),在上面的代碼中,不管是ConcreteDecoratorClass函數(shù)里面的this,還是AbstractDecorator函數(shù)里面的this,都指向new出來(lái)的ConcreteDecoratorClass對(duì)象。

所以,當(dāng)我們執(zhí)行decorator1.performTask()時(shí),它會(huì)繼續(xù)執(zhí)行匿名函數(shù)中的代碼(decorated.performTask();),匿名函數(shù)中的decorated形參指向new出來(lái)的ConcreteClass對(duì)象,并執(zhí)行該對(duì)象的performTask方法。

最后看看實(shí)例3:

var tree = {};
tree.decorate = function () {
 console.log('Make sure the tree won\'t fall');
}; 
tree.getDecorator = function (deco) {
 tree[deco].prototype = this;
 return new tree[deco];
}; 
tree.RedApples = function () {
 this.decorate = function () {
  this.RedApples.prototype.decorate(); // 第7步:先執(zhí)行原型(這時(shí)候是Angel了)的decorate方法
  console.log('Add some red apples'); // 第8步 再輸出 red
  // 將這2步作為RedApples的decorate方法
 }
};
tree.BlueApples = function () {
 this.decorate = function () {
  this.BlueApples.prototype.decorate(); // 第1步:先執(zhí)行原型的decorate方法,也就是tree.decorate()
  console.log('Put on some blue apples'); // 第2步 再輸出blue
  // 將這2步作為BlueApples的decorate方法
 }
}; 
tree.Angel = function () {
 this.decorate = function () {
  this.Angel.prototype.decorate(); // 第4步:先執(zhí)行原型(這時(shí)候是BlueApples了)的decorate方法
  console.log('An angel on the top'); // 第5步 再輸出angel
  // 將這2步作為Angel的decorate方法
 }
};
tree = tree.getDecorator('BlueApples'); // 第3步:將BlueApples對(duì)象賦給tree,這時(shí)候父原型里的getDecorator依然可用
tree = tree.getDecorator('Angel'); // 第6步:將Angel對(duì)象賦給tree,這時(shí)候父原型的父原型里的getDecorator依然可用
tree = tree.getDecorator('RedApples'); // 第9步:將RedApples對(duì)象賦給tree
tree.decorate(); // 第10步:執(zhí)行RedApples對(duì)象的decorate方法
//Make sure the tree won't fall
//Add blue apples
//An angel on the top
//Put on some red apples

實(shí)例3看起來(lái)很復(fù)雜,實(shí)際上分析邏輯還是和前面兩個(gè)實(shí)例一樣,我們可以看出實(shí)例3中一共聲明了5個(gè)函數(shù)表達(dá)式。我們重點(diǎn)分析下下面的代碼:

//tree.getDecorator('BlueApples')返回new出來(lái)的tree.BlueApples的實(shí)例對(duì)象,并將該對(duì)象賦值給空的tree對(duì)象
tree = tree.getDecorator('BlueApples'); //new出來(lái)的tree.BlueApples的實(shí)例對(duì)象的原型指向 --> 空對(duì)象tree 
//tree.getDecorator('Angel')返回new出來(lái)的tree.Angel的實(shí)例對(duì)象(這行代碼中的第二個(gè)tree已經(jīng)是上面一行代碼運(yùn)行結(jié)果后的tree.BlueApples的實(shí)例對(duì)象)
tree = tree.getDecorator('Angel'); //new出來(lái)的tree.Angel的實(shí)例對(duì)象的原型指向 --> tree.BlueApples的實(shí)例對(duì)象
//tree.getDecorator('RedApples')返回new出來(lái)的tree.RedApples的實(shí)例對(duì)象(這行代碼中的第二個(gè)tree已經(jīng)是上面一行代碼運(yùn)行結(jié)果后的tree.Angel的實(shí)例對(duì)象)
tree = tree.getDecorator('RedApples'); //new出來(lái)的tree.RedApples的實(shí)例對(duì)象的原型指向 --> tree.Angel的實(shí)例對(duì)象
//調(diào)用tree.decorate(),這里的tree已經(jīng)是new出來(lái)的tree.RedApples的實(shí)例對(duì)象了。
//tree.RedApples的實(shí)例對(duì)象的decorate屬性方法里面的第一行代碼是 “this.RedApples.prototype.decorate()”
//結(jié)合上面的分析可以得出以下的原型鏈結(jié)構(gòu):
//this.RedApples.prototype --> tree.Angel;
//tree.Angel.prototype --> tree.BlueApples;
//tree.BlueApples.prototype --> 空對(duì)象tree
tree.decorate();

分析到這里,就不難知道最后的輸出結(jié)果了。

三、其他:

我們可以看出本文章中的裝飾者模式案例中用了很多this,對(duì)this不太了解的朋友可以移步到 《深入理解javascript中的 “this”》。

本文案例建議復(fù)制下來(lái)逐行分析,趕緊行動(dòng)起來(lái)吧!

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

最新評(píng)論