成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

學(xué)學(xué)AOP之裝飾者模式

nihao / 1836人閱讀

摘要:但是,這樣做的后果就是,我們會(huì)不斷的改變本體,就像把鳳姐送去做整形手術(shù)一樣。在中,我們叫做引用裝飾。所以,這里引入的裝飾模式裝飾親切,熟悉,完美。實(shí)例講解裝飾上面那個(gè)例子,只能算是裝飾模式的一個(gè)不起眼的角落。

裝飾者,英文名叫decorator. 所謂的"裝飾",從字面可以很容易的理解出,就是給 土肥圓,化個(gè)妝,華麗的轉(zhuǎn)身為白富美,但本體還是土肥圓。

說(shuō)人話.
咳咳~

在js里面一切都是對(duì)象,而且函數(shù)就是一等對(duì)象。 在普通的Object中,我們可以很容易的添加屬性或者其他方法,當(dāng)然函數(shù)也不例外。 但是,這樣做的后果就是,我們會(huì)不斷的改變本體,就像把鳳姐送去做整形手術(shù)一樣。 當(dāng)然,結(jié)果有好有壞,也許鳳姐就是下一個(gè)angelababy,也許... 所以,為了我們代碼的純潔度(就算你是丑小鴨), 我們可以不動(dòng)刀子的情況下,讓你變得又白又美。

引用裝飾

這個(gè)是裝飾的初級(jí)階段,就是抹點(diǎn)粉而已。 在js中,我們叫做引用裝飾。

talk is cheap, show u code

//我們給jimmy函數(shù)額外添加其他的功能
var jimmy = function(){
    console.log("jimmy");
}
var _jimmy = jimmy;
jimmy = function(){
    _jimmy();
    console.log("I love HuaHua");
}
jimmy();

這個(gè)的應(yīng)用場(chǎng)景主要就是在多人協(xié)作和框架設(shè)計(jì)里面。比如,李冰巖已經(jīng)使用了onload函數(shù),但是,小舟又想使用onload函數(shù)。 這樣會(huì)造成一個(gè)問題,如果小舟直接改動(dòng)的話,他需要看的是李冰巖寫的蜜汁代碼,而且還要防止不會(huì)引起錯(cuò)誤。這無(wú)疑是很困難的,所以在這里,可以使用引用裝飾,來(lái)給onload在添加一層。

//這是小李的蜜汁代碼
var xiaoLi = function(){
    console.log("蜜汁代碼");
}
window.onload = xiaoLi;  //小李已經(jīng)綁定好onload函數(shù)了
//接下來(lái)小舟需要改動(dòng)onload代碼
var fn = window.onload;
var xiaoZhou = function(){
    fn();
    conosle.log("整潔代碼");
}
window.onload = function(){  //根據(jù)onload的特性,直接覆蓋掉小李的code
    xiaoZhou();
}

所以引用裝飾的用處還是蠻大的。
大你妹啊~~
啊。。。。
(另一Me) 我們來(lái)分析一下,上面那個(gè)引用模式有什么弊端(好處已經(jīng)都知道了).
首先,我們使用引用模式的時(shí)候,必定會(huì)添加一個(gè)多余的引用對(duì)象,比如上文的"fn".
而且隨著你程序鏈的增加,中間對(duì)象一定會(huì)和你節(jié)點(diǎn)同等數(shù)量的。當(dāng)然,起名我就不說(shuō)了,關(guān)鍵是,一大堆無(wú)用的代碼放在那里,感覺很不爽的。 所以,這里引入AOP的裝飾模式.

AOP裝飾

親切,熟悉,完美。 我們見過(guò)AOP應(yīng)該不止一次了,在職責(zé)鏈模式使用過(guò),在迭代器模式使用過(guò)等等。使用這么多次,好像還沒有對(duì)AOP做一些基本解釋呢?所以,這里給大家咻咻.
AOP中文名叫面向切面編程。 先說(shuō)一下這個(gè)名詞,“面向”這詞應(yīng)該不用解釋,關(guān)鍵"切面"是什么鬼。 如果大家做過(guò)sangwich,應(yīng)該就知道,首先我們買來(lái)一塊面包,需要將面包切開,然后在切面上面加上一些flavoring,比如蔬菜,火腿,培根之類的。 恩,對(duì)比js程序來(lái)說(shuō),一個(gè)程序鏈就相當(dāng)于你買回來(lái)的面包,flavoring就是你想加的功能函數(shù),如何將函數(shù)正確的放置在程序鏈中合適的位置,這就是AOP做的事情。
首先,再次將兩個(gè)動(dòng)態(tài)函數(shù)咻咻:

Function.prototype.after = function(fn){
    var _this = this;
    return function(){
        var res = _this.apply(this,arguments);
        fn.apply(this,arguments);
        return res;
    }
}
Function.prototype.before = function(fn){
    var _this = this;
    return function(){
        fn.apply(this,arguments);  
        return    _this.apply(this,arguments);
    }
}

這兩個(gè)函數(shù)的組合構(gòu)成了js中AOP模式的精華.而AOP最常用的就是講與業(yè)務(wù)邏輯無(wú)關(guān)的功能動(dòng)態(tài)織入到主程序中。

talk is cheap , show u code

舉個(gè)栗子吧: 使用AOP計(jì)算程序運(yùn)行事件

//純手寫計(jì)算函數(shù)運(yùn)行事件
function factorial(n) {  //最基本的階乘計(jì)算
  if (n === 1) return 1;
  return n * factorial(n - 1);
}
function calTime(n){
    var start = new Date().getMilliseconds();
    factorial(n);
    console.log(new Date().getMilliseconds() - start+"ms");
}
calTime(1000);

可以得出耗費(fèi)的時(shí)間,但是,如果還有其他的函數(shù)需要測(cè)試,那么這么做的意義并沒有很大的價(jià)值。我們使用AOP進(jìn)行重構(gòu)。

function factorial(n) {  //最基本的階乘計(jì)算
  if (n === 1) return 1;
  return n * factorial(n - 1);
}
var calTime = (function(){
    var start;
    return    function(){
        if(!start){  //給開始時(shí)間賦值
            start = new Date().getMilliseconds();
        }else{
            console.log(new Date().getMilliseconds()-start+"ms");
            start = undefined;
        }
    }
})();
var calcu = factorial.before(calTime).after(calTime)(200);

這樣很好的將計(jì)時(shí)功能從業(yè)務(wù)邏輯中提取出來(lái),而且看著真的很有angelababy的味道誒.
使用AOP的時(shí)候需要注意一點(diǎn)就是,before&after執(zhí)行完后,返回的結(jié)果都是第一個(gè)函數(shù)的內(nèi)容。

var result = function(){
    return 1;
}.before(function(){
    return 2;
}).after(function(){
    return 3;
});
console.log(result());  //1

我們大致的了解了AOP的用法和理論,可以針對(duì)于開頭所說(shuō)的例子進(jìn)行重構(gòu).

window.onload = function(){
    console.log("小李的蜜汁代碼");
}
var fn = window.onload;
fn.before(function(){
    console.log("整潔代碼");
});
window.onload = fn;

看起來(lái),比上面那個(gè)栗子清晰很多,而且使用before和after也十分利于代碼的閱讀。

實(shí)例講解AOP裝飾

上面那個(gè)例子,只能算是AOP裝飾模式的一個(gè)不起眼的角落。 AOP引用的場(chǎng)景在js中,或者說(shuō)在任何一門語(yǔ)言中都是大放光彩的。 在js中,"細(xì)粒度"對(duì)象是程序中復(fù)用性最高的對(duì)象,能把對(duì)象用細(xì)粒度的形式表示,那么AOP無(wú)疑是最佳的選擇。
在寫業(yè)務(wù)邏輯的時(shí)候,我們最大的問題就是判斷邏輯,使用大量的if語(yǔ)句,而這都可以經(jīng)過(guò)思考巧妙化解。比如,我在寫購(gòu)買課程的時(shí)候就會(huì)遇到一些邏輯。 只有當(dāng)課程數(shù)目符合要求的時(shí)候,購(gòu)買的效果才能有效.
按正常的業(yè)務(wù)邏輯編寫

var buy = function(){
    if(confirm()){  //驗(yàn)證購(gòu)買信息是否合法
        http.buyCourse("xxx");  //發(fā)起請(qǐng)求
    }
}
var confirm = function(){
    console.log("驗(yàn)證購(gòu)買數(shù)量");
}
document.querySelector(".buy").addEventListener("click",function(){
    buy();
},false);

使用AOP裝飾模式重構(gòu)后

var buy = function(){
    http.buyCourse("xxx"); //給后臺(tái)發(fā)起請(qǐng)求,驗(yàn)證
}
var confirm = function(){
    console.log("驗(yàn)證購(gòu)買數(shù)量");
}
var buy = buy.before(confirm);
document.querySelector(".buy").addEventListener("click",function(){
    buy();
},false);

美美代碼的 滿滿即視感?。?!
不夠,老板,再來(lái)份糖炒栗子~
好嘞~
這里我們只是獲取函數(shù)的結(jié)果,那我們想直接干預(yù)傳遞的參數(shù),可以嗎?
當(dāng)然可以。
我們研究一下,before的內(nèi)部構(gòu)造(after是一樣的)

Function.prototype.before = function(fn){
    var _this = this;
    return function(){
        fn.apply(this,arguments);  
        return    _this.apply(this,arguments);
    }
}

這里,由于arguments是引用類型,如果fn改變了arguments,則會(huì)反映到_this.apply的arguments也會(huì)發(fā)生改變。 而這個(gè)應(yīng)用場(chǎng)景就是,給ajax的地址添加上你需要的參數(shù)。
在實(shí)際項(xiàng)目中,一開始的接口,就是一個(gè)普普通通的地址,發(fā)請(qǐng)求,然后獲取參數(shù)。

http.ajax(url,type).then(...)

想這樣的使用,但是某天,你的leader提高了要求等級(jí),將地址后面都加上一個(gè)token參數(shù),或者說(shuō)一個(gè)口令的md5或sha1的計(jì)算值,我想,這尼瑪工作量應(yīng)該不小。
當(dāng)然,我們可以直接將url進(jìn)行傳遞。

var http = {
    ajax1(url){
        url += param.getToken();
        sendAjax(url);
    },
    ajax2(url){
        ...
    }
    ...
}

而且,萬(wàn)一哪天你的leader說(shuō),哎,這樣做安全性還是不太高,要不加兩個(gè)token混淆一下。
啊~啊~啊~啊~(混淆你妹啊,過(guò)不過(guò)年啦)
如果你繼續(xù)這么寫,我相信,年終獎(jiǎng)是有的,但是,春運(yùn)火車票你估計(jì)是摸不著了。
所以可以使用AOP進(jìn)行動(dòng)態(tài)織入。要知道,參數(shù),我AOP也是可以動(dòng)的。

function dealUrl(url){
    url+=param.getToken();
}
http.ajax = http.ajax.before(dealUrl);
http.ajax("www.example.com");   //此時(shí)的Url = www.example.com?token=23jkfd3kjfdksjfkjds

而且,這個(gè)處理url函數(shù),我也是可以扔到任意一個(gè)js文件里面復(fù)用的耶.
棒!!!
我AOP可以動(dòng)你要的參數(shù),而且,我還可以把我的結(jié)果給你是咻咻,如果我不讓你執(zhí)行,你永遠(yuǎn)也不會(huì)執(zhí)行,哈哈哈哈~~~~
對(duì)不起,,上面那段是我意淫AOP說(shuō)的。。。 其實(shí)AOP可以算是萬(wàn)能的配置工具,比如表單驗(yàn)證吧。 我們經(jīng)常會(huì)把表單驗(yàn)證和表單結(jié)果發(fā)送耦合在一起。
像這樣

var sendRes = function(){
    if(user.userName === ""){
        alert("用戶名不能為空~");
        return;
    }else if(user.password === ""){
        alert("密碼不能為空~");
        return;
    }
    http.sendUser("xxx");  //驗(yàn)證成功發(fā)送用戶信息
}

一個(gè)函數(shù)里面同時(shí)含有了兩個(gè)職責(zé),一個(gè)驗(yàn)證一個(gè)發(fā)送用戶信息。 所以我們現(xiàn)在的主要目的就是解耦。
回想一下,以前表單驗(yàn)證我們使用策略模式,解耦了驗(yàn)證,這里我們?cè)俅问褂谩?/p>

var sendRes = function(){
    var detect = new Detect();  //策略者模式
    detect.add(user.userName,["notEmpty"]);
    detect.add(user.password,["notEmpty"]);
    var notPass = detect.getResult();
    if(notPass){  //如果沒通過(guò)
        console.log(notPass);
        return;
    }
    http.sendUser("xxx"); //驗(yàn)證成功發(fā)送用戶信息
}

可以使用上面那個(gè)驗(yàn)證,但是結(jié)果是,驗(yàn)證和策略模式還是在一起。我們?cè)偈褂肁OP進(jìn)行解耦。首先我們得重構(gòu)一下before函數(shù)

Function.prototype.before = function(fn){
    var _this = this;
    return function(){
        var res = fn.apply(this,arguments);  //值為Boolean,表示是否繼續(xù)向下傳遞
        if(res==="next"){  //如果返回不成立,則繼續(xù)向下傳遞
            return    _this.apply(this,arguments);
        }
        return res;
    }
}

看到這里,有些同學(xué)應(yīng)該明白是怎么一回事了。沒錯(cuò),就是根據(jù)before里面驗(yàn)證的結(jié)果判斷是否執(zhí)行下個(gè)發(fā)送請(qǐng)求的功能函數(shù)。
當(dāng)然,如果不想污染原型,你也可以自定義一個(gè)函數(shù)。

var before = function(beforeFn,fn){
    return function(){
        var res = beforeFn.apply(this,arguments);
        if(res==="next"){
            return fn.apply(this,arguments);
        }
    }
}

這樣寫也是可以的。
我們先按原型方式寫,這樣直觀一點(diǎn)

var sendRes = function(){
    http.sendUser("xxx"); //驗(yàn)證成功發(fā)送用戶信息
}
sendRes = sendRes.before(function(){
    var detect = new Detect();  //策略者模式
    detect.add(user.userName,["notEmpty"]);
    detect.add(user.password,["notEmpty"]);
    var notPass = detect.getResult();
    if(notPass){  //如果沒通過(guò)
        console.log(notPass);
    }
    return "next";
});

可以看出,驗(yàn)證那部分已經(jīng)完全和發(fā)送用戶信息的功能函數(shù)完全給解耦了。 這樣不僅提高了函數(shù)的重用性,而且也讓你的代碼朝著“細(xì)粒度”方向大步前進(jìn).

辯證裝飾者模式

其實(shí),裝飾者模式和職責(zé)鏈模式的形式是完全一樣的,所以,他們的弊端也是類似的。鏈造的過(guò)長(zhǎng),對(duì)于性能來(lái)說(shuō)就是一次rape.所以,還是那句話,不要為了模式而模式,沒有萬(wàn)能的模式。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78552.html

相關(guān)文章

  • 5 分鐘即可掌握的 JavaScript 裝飾模式AOP

    摘要:下裝飾者的實(shí)現(xiàn)了解了裝飾者模式和的概念之后,我們寫一段能夠兼容的代碼來(lái)實(shí)現(xiàn)裝飾者模式原函數(shù)拍照片定義函數(shù)裝飾函數(shù)加濾鏡用裝飾函數(shù)裝飾原函數(shù)這樣我們就實(shí)現(xiàn)了抽離拍照與濾鏡邏輯,如果以后需要自動(dòng)上傳功能,也可以通過(guò)函數(shù)來(lái)添加。 showImg(https://segmentfault.com/img/bVbueyz?w=852&h=356); 什么是裝飾者模式 當(dāng)我們拍了一張照片準(zhǔn)備發(fā)朋友...

    chunquedong 評(píng)論0 收藏0
  • javascript設(shè)計(jì)模式--裝飾模式

    摘要:裝飾者模式定義裝飾者模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。 裝飾者模式 定義 : 裝飾者(decorator)模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。 在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)地添加一些額外職責(zé) 特點(diǎn) : 可以動(dòng)態(tài)的...

    haoguo 評(píng)論0 收藏0
  • JavaScript裝飾模式

    摘要:用戶名不能為空密碼不能為空校驗(yàn)未通過(guò)使用優(yōu)化代碼返回的情況直接,不再執(zhí)行后面的原函數(shù)用戶名不能為空密碼不能為空 本文是《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》的學(xué)習(xí)筆記,例子來(lái)源于書中,對(duì)于設(shè)計(jì)模式的看法,推薦看看本書作者的建議。 什么是裝飾者模式? 給對(duì)象動(dòng)態(tài)增加職責(zé)的方式成為裝飾者模式。 裝飾者模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在運(yùn)行程序期間給對(duì)象動(dòng)態(tài)地添加職責(zé)。這是一種輕便靈活...

    Taste 評(píng)論0 收藏0
  • 面試官:“談?wù)凷pring中都用到了那些設(shè)計(jì)模式?”。

    摘要:會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎中用到了那些設(shè)計(jì)模式中用到了那些設(shè)計(jì)模式這兩個(gè)問題,在面試中比較常見。工廠設(shè)計(jì)模式使用工廠模式可以通過(guò)或創(chuàng)建對(duì)象。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問題,已經(jīng)開源,目前已經(jīng) 41k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://github.com/Snailclimb... JDK 中用到了那...

    Astrian 評(píng)論0 收藏0
  • Spring AOP(二) 修飾模式和JDK Proxy

    摘要:修飾者模式設(shè)計(jì)模式中的修飾者模式能動(dòng)態(tài)地給目標(biāo)對(duì)象增加額外的職責(zé)。修飾者模式調(diào)用的時(shí)序圖如下圖所示。的實(shí)現(xiàn)原理和修飾者模式類似。 ?在上邊一篇文章中我們介紹了Spring AOP的基本概念,今天我們就來(lái)學(xué)習(xí)一下與AOP實(shí)現(xiàn)相關(guān)的修飾者模式和Java Proxy相關(guān)的原理,為之后源碼分析打下基礎(chǔ)。 修飾者模式 ?Java設(shè)計(jì)模式中的修飾者模式能動(dòng)態(tài)地給目標(biāo)對(duì)象增加額外的職責(zé)(Respon...

    Jackwoo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<