javascript设计模式学习之十五——装饰者模式
一、装饰者模式定义
装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。这种为对象动态添加职责的方式就称为装饰者模式。装饰者对象和它所装饰的对象拥有一致的接口,对于用户来说是透明的。
和java等语言不同的是,java的装饰器模式是给对象动态添加职责,javascript中,给对象添加职责的能力是与生俱来的,更侧重于给函数动态添加职责。
二、java中的装饰者模式实现
package com.bobo.shejimoshi.derector; public class Plane { public void fire(){ System.out.println("发射普通子弹"); } }
package com.bobo.shejimoshi.derector; public class MissileDecorator { private Plane plane; public MissileDecorator(Plane plane){ this.plane=plane; } public void fire(){ plane.fire(); System.out.println("发射导弹"); } }
可见在java等传统语言中,给对象动态增加职责的方式,并没有真正地改动对象自身,而是将对象放入另一个对象之中,这些对象都具有相同的对外接口。
三、javascript中的装饰者模式实现
3.1为javascript对象添加职责
在javascript中,给对象添加职责是与生俱来的本领。同样是上面的例子,在javascript中可以这么实现:
//装饰者模式 var plane={ fire:function(){ console.log("发射普通子弹"); }, }; var missileDecorator=function(){ console.log("发射导弹"); }; var fire1=plane.fire; plane.fire=function(){ fire1(); missileDecorator(); }; plane.fire();
3.2为javascript函数添加职责
为函数添加一些功能,在java等语言中貌似只能直接改写该函数,这显然违反了开放—封闭原则;
如果不想更改原函数,可以像上面的例子,通过保存原函数引用的方式来改写某个函数,这种方式一种是需要借助中间变量保存原函数的引用,此外还会遇到this劫持的问题。
因此,比较好的方式是利用AOP来进行函数装饰。
Function.prototype.before
Function.prototype.before=function(beforeFn){ var _self=this;//保存原函数的引用 return function(){ beforeFn.apply(this,arguments); return _self.apply(this,arguments); }; }; document.getElementById=document.getElementById.before(function(){ alert(1); }); var sel=document.getElementById('colorSelect');
如果想根据上一个函数的执行结果决定函数是否执行,甚至还可以这样写Function.prototype.before
Function.prototype.before=function(beforeFn){ var _self=this; return function(){ if(beforeFn.apply(this,arguments)!==false){ _self.apply(this,arguments); } }; };
使用这种方法还可以动态改变函数的参数:
var func=function(param){ console.log(param); }; func=func.before(function(param){ param.b='b'; }); func({'a':'a'});//输出 'a':a,'b':b
Function.prototype.after
Function.prototype.after=function(afterFn){ var _self=this; return function(){ var ret=_self.apply(this,arguments); afterFn.apply(this,arguments); return ret; }; };