这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战
装饰者模式
下面我们来学习装饰者模式,首先什么是装饰者模式呢?
装饰者模式就是在不侵入原来的类的情况下,改变或者拓展它。
我们来看这个例子:
// Phone.ts
export default class Phone {
getPrice() {
return 1000;
};
call() {
console.log('calling');
}
}
复制代码
接下来,我们想给这个手机添加手机壳,我们可以添加一个装饰者。
一个装饰者其实就是普通的 function。
// addCase.ts
import Phone from './Phone';
// 添加手机壳
export default function addCase(P: typeof Phone) {
return class extends P {
getPrice() {
return super.getPrice() + 50;
}
}
}
复制代码
那我们如何使用这个装饰者呢?首先我们还是要引入装饰器,修改下面这样,这样就实现了给这个手机添加手机壳
// Phone.ts
import addCase from './addCase';
class Phone {
getPrice() {
return 1000;
};
call() {
console.log('calling');
}
}
export default addCase(Phone);
复制代码
我们在使用它的时候,getPrice 就可以返回 1050。
// index.ts
import Phone from './Phone';
let p = new Phone();
console.log(p.getPrice()); // 1050
复制代码
除了这种直接调用装饰器的方式,我们还可以使用更加简便的方式,在 class 前面使用 @ 操作符,然后将 class 标为默认导出。这样也能实现同样的效果。
// Phone.ts
import addCase from './addCase';
@addCase
export default class Phone {
getPrice() {
return 1000;
};
call() {
console.log('calling');
}
}
复制代码
习题:理解装饰者模式,计算下面结果
答案:
20
解析:
装饰者模式在不改变对象本身的情况下,在程序运行阶段为对象动态增加功能。
ES6 开始用 @
标识装饰器,即 @decorator
,题目中的类 animalDecorator
是一个类装饰器,类装饰器会在运行时当作函数被调用,类的构造函数将作为其唯一的参数。
装饰器中使用了泛型相关知识 <>
(我们将在泛型章节详细介绍)。
为了更好的理解装饰器,我们看看 tsc
编译后的核心代码
const animalDecorator = (constructor) => {
return class extends constructor {
constructor() {
super(...arguments);
this.age = 20;
}
};
};
let Animal = class Animal {
constructor(age) {
this.age = age;
}
};
Animal = __decorate([
animalDecorator
], Animal);
new Animal(10).age;
复制代码
类装饰器 animalDecorator
返回了一个匿名类,记做匿名类 A
下面简称类 A
。类 A
继承于类 Animal
的构造函数。运行时候会先执行类 Animal
的构造函数,在执行类 A
的构造函数,这样也就达到了装饰器的目的。所以答案为 20
。