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;
        };
    };

 

posted @ 2016-07-28 16:00  bobo的学习笔记  阅读(340)  评论(0编辑  收藏  举报