1. 装饰器模式的定义
在不改变其原有的结构和功能为对象添加新功能。
class Coffee{
make(water){
return `${water}+咖啡`;
}
cost(){
return 10;
}
}
class MilkCoffee{
constructor(parent){
this.parent = parent;
}
make(water){
return `${this.parent.make(water)}+牛奶`;
}
cost(){
return this.parent.cost()+1;
}
}
class SugerCoffee{
constructor(parent){
this.parent = parent;
}
make(water){
return `${this.parent.make(water)}+糖`;
}
cost(){
return this.parent.cost()+2;
}
}
let coffee = new Coffee();
let milkCoffee = new MilkCoffee(coffee);
let milksugerCoffee = new SugerCoffee(milkCoffee);
console.log(milksugerCoffee.make('水')+'='+milksugerCoffee.cost());
2. 场景
2.1 AOP
在函数执行之前或之后增加一些逻辑。
Function.prototype.before = function (beforeFn) {
let _this = this;
return function () {
beforeFn.apply(this, arguments);
return _this.apply(this, arguments);
}
}
Function.prototype.after = function (afterFn) {
let _this = this;
return function () {
_this.apply(this, arguments);
afterFn.apply(this, arguments);
}
}
2.2 埋点
埋点分析,是网站分析的一种常用的数据采集方法。
<body>
<button data-name="西瓜" id="watermelon">西瓜</button>
<button data-name="苹果" id="apple">苹果</button>
<script>
let watermelon = document.getElementById('watermelon');
let apple = document.getElementById('apple');
Function.prototype.after = function (afterFn) {
let _this = this;
return function () {
_this.apply(this, arguments);
afterFn.apply(this, arguments);
}
}
function click() {
console.log('点击' + this.dataset.name);
}
click = click.after(function () {
let img = new Image();
img.src = `http://localhost:3000?name=${this.dataset.name}`;
});
Array.from(document.querySelectorAll('button')).forEach(function (button) {
button.addEventListener('click', click);
});
</script>
</body>
let express = require('express');
let app = express();
app.get('/',function(req,res){
console.log('name',req.query.name);
res.end('ok');
});
app.listen(3000);
3. 总结
装饰者模式和代理模式的结构看起来非常相像,这两种模式都描述了怎样为对象提供 一定程度上的间接引用,它们的实现部分都保留了对另外一个对象的引用,并且向那个对象发送 请求。
代理模式的目的是,当直 接访问本体不方便或者不符合需要时,为这个本体提供一个替代者。本体定义了关键功能,而代 理提供或拒绝对它的访问,或者在访问本体之前做一些额外的事情。装饰者模式的作用就是为对 象动态加入行为。换句话说,代理模式强调一种关系(Proxy 与它的实体之间的关系),这种关系 可以静态的表达,也就是说,这种关系在一开始就可以被确定。而装饰者模式用于一开始不能确 定对象的全部功能时。代理模式通常只有一层代理本体的引用,而装饰者模式经常会形成一条 长长的装饰链。
在虚拟代理实现图片预加载的例子中,本体负责设置 img 节点的 src,代理则提供了预加载 的功能,这看起来也是“加入行为”的一种方式,但这种加入行为的方式和装饰者模式的偏重点 是不一样的。装饰者模式是实实在在的为对象增加新的职责和行为,而代理做的事情还是跟本体 一样,最终都是设置 src。但代理可以加入一些“聪明”的功能,比如在图片真正加载好之前,先使用一张占位的 loading 图片反馈给客户。