【Nest全栈之旅】第二章:我是如何理解装饰器的?

Nest系列概念篇,聊聊装饰器。

装饰器

基本概念

装饰器,顾名思义就是用来装饰某件物体,在一定程度上增加了某件物体的功能,以解决更多的实际需求。

举个栗子🌰,一间房子里面放了一张床,那么就实现了这个房间可以睡觉的基本需求,在这个基础上新增了沙发、红酒杯、电视机,那么就可以实现坐在沙发上摇着红酒看综艺节目的理想状态。此时沙发、红酒杯、电视机起到了装饰器的效果,在不影响房间可以用来睡觉的前提下扩展了更多的功能,实现松耦合和易扩展。

装饰器种类

上个例子中,沙发、红酒杯、电视机属于不同的装饰器,它们分别实现了不同的功能,同样的,常用的装饰器也分为以下几种:

  1. 类装饰器
  2. 方法装饰器
  3. 属性装饰器
  4. 参数装饰器

下面分别用几个简单的例子来说明。

ES6中装饰器使用

typescript 复制代码
/**
 * 类装饰器
 */
const doc: ClassDecorator = (target: any) => {
    target.prototype.name = 'jmin'
    console.log(target);
}
​
@doc
class App {
    constructor() {   
    }
}
​
const app: Record<string, any> = new App()
console.log('app name: ' + app.name);
​
​
/**
 * 属性装饰器
 */
const prop: PropertyDecorator = (target: Object, propertyKey: string | Symbol) => {
    console.log('------属性装饰器-------');
    
    console.log(target);
    console.log(propertyKey);
    
    console.log('------属性装饰器-------');

}
​
class User {
    @prop
    name: string = 'jmin'
}
​
​
/**
 * 方法装饰器
 */
const method: MethodDecorator = (target: Object, propertyKey: string | Symbol, descriptor: PropertyDescriptor) => {
    console.log("---------------方法装饰器-----------------");
    console.log(target);
    console.log(propertyKey);
    console.log(descriptor);
    console.log("---------------方法装饰器-----------------");
}
​
class User2 {
    @method
    getName() {
        return 'jmin';
    }
}
​
/**
 * 参数装饰器
 */
​
const param: ParameterDecorator = (target: Object, propertyKey: string | Symbol | undefined, index: number) => {
    console.log('-------------参数装饰器------------------');
    console.log(target);
    console.log(propertyKey);
    console.log(index);
    console.log('-------------参数装饰器------------------');   
}
​
class User3 {
    
    getName(@param name: string) {
        return name;
    }
}
​
const user3 = new User3();
console.log(user3.getName('jmin'));
​

Nest中的装饰器

nest中实现AOP思想的一种方式就是用装饰器,这些装饰器分为异常过滤器(exception filter)管道(pipes)守卫(guards)拦截器(interceptors)等等

扩展一个题外话,为什么nest中要实现AOP架构?

当一个请求过来的时候,一般会通过Controller控制器Services服务层Repository数据访问实体链路,当我们不使用AOP时,需要新增一些通用逻辑如(权限控制、日志统计、异常处理),就需要在每个请求逻辑中编写编写相关代码,这必然造成业务逻辑跟通用逻辑的耦合而让应用变得难以维护。

AOP切面思想是将所有请求外面包裹一层,所有的请求都会通过这个切面去处理通用逻辑,实现了业务逻辑松耦合和易扩展。

再回来看一下Nest中基础的装饰器:

typescript 复制代码
// person.controller.ts

@Controller('person')
export class PersonController {
  constructor(private readonly personService: PersonService) {}
​
  @Post('/create-person')
  create(@Body() createPersonDto: CreatePersonDto) {
    return this.personService.create(createPersonDto);
  }
}

上面可以看到,存在类装饰器、方法装饰器、参数装饰器 ,可以发现它们是支持接受参数或直接调用,如@Controller('person'),但是ES6中不支持直接调用装饰器啊,那是怎么实现呢?

答案是通过装饰器工厂,也叫柯里化

看下面的例子你就懂了:

typescript 复制代码
const doc2 = (param: string) : ClassDecorator => {
    console.log("param:", param);
    return (target: any) => {
        target.prototype.name = 'jmin'
        console.log(target);
    }
}
​
@doc2('person')
class App2 {
    constructor() {   
    }
}
​
const app2: Record<string, any> = new App2()
console.log('app2 name: ' + app2.name);

这就实现了跟Nest中相同的装饰器语法,实际上,Nest中恰恰也是通过这种方式来实现的。

Get(':id')请求装饰器为例:

这里接受的path参数就是:id这串玩意~

总结

通过类比方式介绍了装饰器本身,为了装饰某件物体才能够产生价值。

接着介绍装饰器的几种存在形态,以及ES6的基本实现,还介绍了Nest中装饰器的应用场景以及跟AOP思想的融合,最后翻了一下源码看Nest中装饰器的基本实现,一眼就看出跟ES6中实现的区别。

但,这不是全部,要实现Nest中的装饰器效果,还有一个很重要的概念就是元数据反射,它们有什么作用呢?存在的意义又是什么?

欲知后事如何,请看下节分享!!!

相关推荐
To_OC8 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic8 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy8 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志8 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble10 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯10 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
戮漠summer11 小时前
Missing Semester 计算机教育中缺失的一课 Lecture 01 Shell
开发语言·后端·scala
名字还没想好☜11 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司11 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
kaiking_g12 小时前
vue项目中,静态导入 vs 动态导入 详解
前端·javascript·vue.js