【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中的装饰器效果,还有一个很重要的概念就是元数据反射,它们有什么作用呢?存在的意义又是什么?

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

相关推荐
BigTopOne1 分钟前
Ubuntu 虚拟机编译 WebRTC Android AAR(M140 / branch-heads/7339)
前端
默_笙1 分钟前
🍕 后端接口还没写好,前端已经跑起来了?Mock 数据 + axios 接口层,前后端再也不互相"等"
前端·javascript
书源4 分钟前
AI 时代写给前端同行:什么在贬值,什么在涨价
前端·程序员·ai编程
爱勇宝14 分钟前
客户只想看个页面,我却做了一个静态演示发布系统
前端·javascript·后端
渔夫正在掘金16 分钟前
告别构建时代:为什么 AI 编程浪潮正让 Vue 与 React 走向落后?
前端
一个有理想的摸鱼选手26 分钟前
(四)路书Agnet-综合天气距离交通节奏等多因素来编排旅行路线
前端·后端·gis
神奇的程序员28 分钟前
在这个独属于ai的时代,我终究是被裁员了
前端·后端·面试
云边有个稻草人31 分钟前
从单机工具到“云+端+服务”:KDMS数据库迁移工具如何支撑大型信创项目协同作战
后端
玉宇夕落32 分钟前
React + JWT 登录鉴权系统
前端