装饰者可以透明地把对象包装在具有同样接口的另一对象中。
装饰者模式的实现
装饰者可用于为对象增加功能,可以替代大量子类。
function Bicycle() {
}
Bicycle.prototype.getPrice = function (){
return 399;
}
Bicycle函数用于构造Bicycle实例对象,在没有其他部件的情况下price属性的值为399
// 继承函数
function extend(subClass, supClass){
function F(){}
F.prototype = supClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = supClass.prototype;
}
继承函数用于子装饰器类继承父装饰器类,用于简化子装饰器类的书写
// 装饰者父类
function Decorator(bicycle) {
this.bicycle = bicycle;
}
Decorator.prototype.getPrice = function() {
return this.bicycle.getPrice();
}
装饰者父类作为子装饰者构造函数的模板,保证具有相同的接口,getPrice()方法用于返回被装饰后的Bicycle的price
// HeadLightDecorator装饰类
function HeadLightDecorator(bicycle) {
HeadLightDecorator.superclass.constructor.call(this, bicycle);
}
extend(HeadLightDecorator, Decorator);
HeadLightDecorator.prototype.getPrice = function () {
return this.bicycle.getPrice() + 15;
}
// TaillightDecorator装饰类
function TaillightDecorator(bicycle) {
TaillightDecorator.superclass.constructor.call(this, bicycle);
}
extend(TaillightDecorator, Decorator);
TaillightDecorator.prototype.getPrice = function () {
return this.bicycle.getPrice() + 20;
}
子装饰者类,用于创建装饰者,即返回包装Bicycle对象后的对象
let myBicycle = new Bicycle();
console.log(myBicycle.getPrice());
myBicycle = new HeadLightDecorator(myBicycle);
console.log(myBicycle.getPrice());
myBicycle = new TaillightDecorator(myBicycle);
console.log(myBicycle.getPrice());
我们可以看到先输出Bicycle本身的价格属性的值为399,经过HeadLightDecorator包装后返回的价格属性增加15,经过TaillightDecorator包装后在之前的价格属性上再加20,如此实现对原对象的扩展。
装饰者模式与组合模式的比较
相同点:
- 装饰者和组合模式都是用来包装别的对象,它们都与所包装的对象拥有同样的方法,并且会把这些方法的调用传递给被包装的对象。
- 都是结构型模式
不同点
- 组合模式用于把众多子对象组织成一个整体。
- 装饰者不用于组织对象,而是用于在不修改现有对象,或从其派生子类的前提下为其增添职责。
装饰者修改其组件的方式
- 在方法之后添加行为
- 在方法之前添加行为
- 替换方法
- 添加新方法
在Function中使用装饰者模式
Function.prototype.before = function (beofreFn){
let _this = this;
return funciton(){
beforeFn.apply(this, arguments);
_this.apply(this,arguments);
}
}
函数通过before包装后,在函数执行之前先执行beforeFn函数,然后再执行函数本身,实现在函数执行之前执行自定义逻辑的功能
Function.prototype.after = function (afterFn){
let _this = this;
return function (){
_this.apply(this, arguments);
afterFn.apply(this, arguments);
}
}
使用after对函数包装后,函数执行自身后执行afterFn函数,实现在函数执行后执行自定义逻辑的功能。