设计模式之装饰者模式

Posted by franki on November 9, 2018

decorator

装饰者模式 装饰者模式的作用就是为对象动态加入行为
装饰者模式经常会形成一条长长的装饰链

// 装饰者模式
var Plane = function() {};

Plane.prototype.fire = function() {
    console.log("发射普通子弹");
};

var daodan = function(plane) {
    this.plane = plane;
};

daodan.prototype.fire = function() {
    this.plane.fire();
    console.log("发射导弹");
};

var automatic = function(plane) {
    this.plane = plane;
};

automatic.prototype.fire = function() {
    this.plane.fire();
    console.log("发射原子弹");
};

var plane = new Plane(),
    ss = new daodan(plane),
    sss = new automatic(ss);

sss.fire();

// javascript 实现装饰者模式
var plane = {
    fire: function() {
        console.log("发射普通子弹");
    }
};

var fire1 = plane.fire;

var daodan = {
    fire: function() {
        fire1();
        console.log("发射导弹");
    }
};

var fire2 = daodan.fire;

var automatic = {
    fire: function() {
        fire2();
        console.log("发射原子弹");
    }
};

automatic.fire();

```js
这种给对象动态增加职责的方式,并没有真正地改动对象自身,而是将对象放入另一个对象之中,这些对象以一条链的方式进行引用,形成一个聚合对象。
这些对象都拥有相同的接口(fire方法),当请求达到链中的某个对象时,这个对象会执行自身的操作,随后把请求转发给链中的 下一个对象  

```js
// AOP 实现装饰者模式
Function.prototype.before = function(beforeFn) {
    var self = this;

    return function() {
        beforeFn.apply(this, arguments);
        return self.apply(this, arguments);
    };
};

Function.prototype.after = function(afterFn) {
    var self = this;

    return function() {
        var ret = self.apply(this, arguments);
        afterFn.apply(this, arguments);
        return ret;
    };
};

(window.onload || function() {})
.before(function() {
    console.log(1);
})
.before(function() {
    console.log(2);
})
.before(function() {
    console.log(3);
})();

// 不污染原型链的做法
var before = function(fn, beforefn) {
    return function() {
        beforefn.apply(this, arguments);
        return fn.apply(this, arguments);
    };
};
var a = before(
    function() {
        console.log(4);
    },
    function() {
        console.log(5);
    }
);

a = before(a, function() {
    console.log(6);
});
a = a();

// 装饰者模式会动态改变arguments
Function.prototype.before = function(beforeFn) {
    var self = this;
        return function() {
        beforeFn.apply(this, arguments);
        return self.apply(this, arguments);
    };
};

var func = function(param) {
    console.log(param);
};

func = func.before(function(param) {
    param.b = "b";
});
func({ a: "a" });
// 装饰者模式应用在表单提交
Function.prototype.before = function(beforeFn) {
    var self = this;
    return function() {
    if (!beforeFn.apply(this, arguments)) {
    return;
    }
    return self.apply(this, arguments);
    };
};

function submit(name) {
    console.log("submit success, name: ", name);
}

function validate(name) {
    if (!name) {
    console.log("name is not arrowed empty, not arrowed to submit");
    return false;
    }
    return true;
}

function init() {
    var div = document.createElement("div");
    div.innerHTML =
    '<p><label>name</label> <input id="username" placeholder="please input your name"/></p><p><button id="submit">submit</button></p>';
    document.body.appendChild(div);

    var sub = document.getElementById("submit");
    var test = submit.before(validate);
    sub.onclick = function() {
    var value = document.getElementById("username").value;
    test(value);
    };
}

init();

用AOP实现职责链既简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能有影响。