代码改变世界

javascript装饰者模式

2010-01-31 23:28  BlueDream  阅读(835)  评论(0编辑  收藏  举报

装饰模式:Decorator常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这两种实体在Decorator模式中是必须的.

Decorator定义:
动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.

使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator提供了"即插即用"的方法,在运行期间决定何时增加何种功能.

[简易实例]

<script type="text/javascript">
 var f = function() {
    alert('原有函数');
 }
 var _f = f;
 f = function() {
    alert('执行前置包装函数');
    _f();
    alert('执行后置包装函数');
 }
 f();
</script>

[常用实例] ---- 多重onload绑定

<script type="text/javascript">
function addLoadEvent(fn) {
    var oldEvent = window.onload;
    if(typeof window.onload != 'function') {
        window.onload = fn;
    }else {
        window.onload = function() {
            oldEvent();
            fn();
        }
    }
}
function fn1() {
    alert('加载一');
}
function fn2() {
    alert('加载二');
}
function fn3() {
    alert('加载三');
}
addLoadEvent(fn1);
addLoadEvent(fn2);
addLoadEvent(fn3);
</script>

[扩展实例]

<script type="text/javascript">
// 被刷油漆者
Decoratee = function() {
    alert('被刷油漆');
}
// 刷油漆工
Decorator = {
    beginList: [],    // 前置函数列表
    endList: [],    // 后置函数列表
    append: function(fn) {
        this.endList.push(fn);
    },
    before: function(fn) {
        this.beginList.splice(0, 0, fn);
    },
    wrap: function(fn/* 要被修饰的函数体 */) {
        var $ = this, $1 = [], $2 = [];
        // 包装前置函数
        for(var i = 0, len = $.beginList.length; i < len; i++) {
            $1[i] = $.beginList[i];
        }
        // 包装后置函数
        for(var i = 0, len = $.endList.length; i < len; i++) {
            $2[i] = $.endList[i];
        }

        try {
            return function(){
                for(var i = 0, len = $1.length; i < len; i++) {
                    $1[i]();
                }
                if(typeof fn == 'function') fn();
                for(var i = 0, len = $2.length; i < len; i++) {
                    $2[i]();
                }
            }
        }finally {
            this.beginList.length = this.endList.length = 0;
        }
    }
}

Decorator.before(function() { alert('刷油漆前先钉木头') });
Decorator.before(function() { alert('刷油漆前先钉钉子') });
Decorator.append(function() { alert('刷油漆后要晾干') });
Decorator.append(function() { alert('刷油漆后要涂鸦') });
Decorator.wrap(Decoratee)(); // 开始刷油漆
</script>