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

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

相关推荐
跟着珅聪学java2 分钟前
spring boot +Elment UI 上传文件教程
java·spring boot·后端·ui·elementui·vue
吞掉星星的鲸鱼5 分钟前
使用高德api实现天气查询
前端·javascript·css
lilye668 分钟前
程序化广告行业(55/89):DMP与DSP对接及数据统计原理剖析
java·服务器·前端
徐小黑ACG1 小时前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
zhougl9962 小时前
html处理Base文件流
linux·前端·html
花花鱼2 小时前
node-modules-inspector 可视化node_modules
前端·javascript·vue.js
HBR666_2 小时前
marked库(高效将 Markdown 转换为 HTML 的利器)
前端·markdown
战族狼魂4 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
careybobo4 小时前
海康摄像头通过Web插件进行预览播放和控制
前端
杉之5 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue