JavaScript設計模式----裝飾者模式

裝飾者模式的定義:

裝飾者(decorator)模式可以在不改變對象自身的基礎上,在程序運行期間給對像動態的添加職責。與繼承相比,裝飾者是一種更輕便靈活的作法。javascript

裝飾者模式的特色:

能夠動態的給某個對象添加額外的職責,而不會影響從這個類中派生的其它對象;java

繼承的一些缺點:

  1. 繼承會致使超類和子類之間存在強耦合性,當超類改變時,子類也會隨之改變;git

  2. 超類的內部細節對於子類是可見的,繼承經常被認爲破壞了封裝性;github

傳統面向對象的裝飾者和JavaScript裝飾者對比:

1.模擬傳統面嚮對象語言的裝飾者模式

//模擬傳統語言的裝飾者 //原始的飛機類 var Plan = function () { }; Plan.prototype.fire = function () { console.log('發射普通子彈'); }; //裝飾類 var MissileDecorator = function (plan) { this.plan = plan; } MissileDecorator.prototype.fire = function () { this.plan.fire(); console.log('發射導彈!'); }; var plan = new Plan(); plan = new MissileDecorator(plan); plan.fire();

2.JavaScript中的裝飾者模式

裝飾者模式將一個對象嵌入到另外一個對象之中,實際上至關於這個對象被另外一個對像包裝起來,造成一條包裝鏈。請求隨着這條包裝鏈依次傳遞到全部的對象,每一個對象都有處理這條請求的機會。ajax

var Plan1 = { fire: function () { console.log('發射普通的子彈'); } }; var missileDecorator= function () { console.log('發射導彈!'); }; var fire = Plan1.fire; Plan1.fire=function () { fire(); missileDecorator(); }; Plan1.fire(); 

裝飾函數

在JavaScript中能夠很方便的給某個對象擴展屬性和方法,但卻很難在不改動某個函數源代碼的狀況下,給該函數添加一些額外的功能。也就是在代碼運行期間,咱們很難切入某個函數的執行環境。編程

1.使用裝飾者模式例子

//對window.onload的處理 window.onload=function () { console.log('test'); }; var _onload= window.onload || function () {}; window.onload=function () { _onload(); console.log('本身的處理函數'); };

2.使用AOP(面向切面編程)裝飾函數

主要是覺得在JavaScript中會存在隨着函數的調用,this的指向發生變化,致使執行結果發生變化。markdown

2.1.封裝的before函數

在須要執行的函數以前執行某個新添加的功能函數app

//是新添加的函數在舊函數以前執行 Function.prototype.before=function (beforefn) { var _this= this; //保存舊函數的引用 return function () { //返回包含舊函數和新函數的「代理」函數 beforefn.apply(this,arguments); //執行新函數,且保證this不被劫持,新函數接受的參數 // 也會被原封不動的傳入舊函數,新函數在舊函數以前執行 return _this.apply(this,arguments); }; };
2.2.封裝的after函數

在須要執行的函數以後執行某個新添加的功能函數函數

//新添加的函數在舊函數以後執行 Function.prototype.after=function (afterfn) { var _this=this; return function () { var ret=_this.apply(this,arguments); afterfn.apply(this,arguments); return ret; }; };
2.3.不污染Function原型的作法
var before=function (fn, before) { return function () { before.apply(this,arguments); return fn.apply(this,arguments); }; }; function func1(){console.log('1')} function func2() {console.log('2')} var a=before(func1,func2); // a=before(a,func1); a();

裝飾者模式用法示例:

1.ajax動態添加參數

使用裝飾者模式動態的改變ajax函數,傳輸的參數post

//是新添加的函數在舊函數以前執行 Function.prototype.before=function (beforefn) { var _this= this; //保存舊函數的引用 return function () { //返回包含舊函數和新函數的「代理」函數 beforefn.apply(this,arguments); //執行新函數,且保證this不被劫持,新函數接受的參數 // 也會被原封不動的傳入舊函數,新函數在舊函數以前執行 return _this.apply(this,arguments); }; }; var func = function (param) { console.log(param); }; func = func.before(function (param) { param.b = 'b'; }); func({b:'222'}); //給ajax請求動態添加參數的例子 var ajax=function (type,url,param) { console.log(param); }; var getToken=function () { return 'Token'; }; ajax=ajax.before(function (type, url, param) { param.token=getToken(); }); ajax('get','http://www.jn.com',{name:'zhiqiang'});

2.表單驗證而且提交

裝飾者模式分離表單驗證和提交的函數

Function.prototype.before=function (beforefn) { var _this= this; //保存舊函數的引用 return function () { //返回包含舊函數和新函數的「代理」函數 beforefn.apply(this,arguments); //執行新函數,且保證this不被劫持,新函數接受的參數 // 也會被原封不動的傳入舊函數,新函數在舊函數以前執行 return _this.apply(this,arguments); }; }; var validata=function () { if(username.value===''){ alert('用戶名不能爲空!') return false; } if(password.value===''){ alert('密碼不能爲空!') return false; } } var formSubmit=function () { var param={ username=username.value; password=password.value; } ajax('post','http://www.mn.com',param); } formSubmit= formSubmit.before(validata); submitBtn.onclick=function () { formSubmit(); }

總結:

裝飾者模式和代理模式的區別:

  1. 代理模式的目的是,當直接訪問本體不方便或者不符合須要時,爲這個本體提供一個代替者。本體定義了關鍵功能,而代理提供了或者拒絕對他的訪問,或者是在訪問本體以前作一些額外的事情。

  2. 裝飾者模式的做用就是爲對象動態的加入某些行爲。


圖片名稱

相關文章
相關標籤/搜索