设计模式学习之九-装饰者模式

装饰者模式的使用场景: 为对象扩展方法,且不影响原对象。

场景

我们声明了一个匿名函数

1
2
3
function test() {
console.log('test')
}

现在如果我们要扩展该方法,比较保守的做法的是直接修改该方法

1
2
3
4
5
function test() {
// 添加新操作
console.log('test');
// 添加新操作
}

现在我们用装饰者模式来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Function.prototype.before = function ( beforeFn ) {
var __self = this;

return function ( ) {
beforeFn.apply(this, arguments); // before先执行
return __self.apply(this, arguments); // 再执行原本的方法
}
}

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

return function ( ) {
__self.apply(this, arguments); // 执行原本的方法

return afterFn.apply(this, arguments); // 执行after的扩展方法
}
}

var test = function ( ) {
console.log('test')
}

test = test.before(function ( ) {
console.log('before')
})
test = test.after(function ( ) {
console.log('after')
});

test(); // 输出:'before','test','after'

test.before(fn)之后直接赋值覆盖原test方法来实现扩展。

比如我们要在ajax方法中扩展before或after,或者要在表单提交时,验证表单,扩展beofre,就可以使用这种方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Function.prototype.before = function ( beforeFn ) {
var __self = this;

return function ( ) {
if(beforeFn.apply(this, arguments) === false){
return;
} // before先执行
return __self.apply(this, arguments); // 再执行原本的方法
}
}

var validata = function() {
if(username.value === ''){
alert('用户名不能为空');
return false;
}
}

var formSubmit = function() {
ajax(url, params);
}

formSubmit = formSubmit.before(validata);

submitBtn.onclick = formSubmit;

缺点

装饰者模式其实返回的是新方法来覆盖的原方法。所以原对象中的私有属性也会被丢失。并且多次
return叠加了函数作用域,如果作用域链过长,性能会受到影响。