前言
本篇学习下IOC&DI,Reflect Metadata,以及nest中的大致原理。 我主要就是这里比较薄弱,所以看了nest感觉和作者水平差距太大了。
Reflect Metadata
在写nest时候,上面可能会导入reflect metadata 。 官网 https://www.npmjs.com/package/reflect-metadata 官网上说了,使用这玩意需要tsconfig开启2个装饰器按钮:
To enable experimental support for metadata decorators in your TypeScript project, you must add "experimentalDecorators": true to your tsconfig.json file.
To enable experimental support for auto-generated type metadata in your TypeScript project, you must add "emitDecoratorMetadata": true to your tsconfig.json file.
Please note that auto-generated type metadata may have issues with circular or forward references for types.
这个介绍说,这个库目标就是讲元数据修改添加功能统一起来,并且还可以在proxy等上能正常设置获取。为了实现IOC等效果。 基本用法:
Reflect. defineMetadata ( metadataKey, metadataValue, target) ;
Reflect. defineMetadata ( metadataKey, metadataValue, target, property) ;
Reflect. getMetadata ( metadataKey, target) ;
Reflect. getMetadata ( metadataKey, target, property) ;
一个定义和一个获取。getmetadata还有种getOwnMetadata,这个 还自带装饰器
class C {
@Reflect. metadata ( metadataKey, metadataValue)
method ( ) {
}
}
这个效果和用api一个意思,只是用的装饰器来表示。 同时这个装饰器如果在class上面,代表给类的静态增加元数据,而如果在方法上,代表给类的原型对象加(简单可以理解为加在哪就是定义哪) 这个reflect.metadata装饰器其实相当于这样:
function classMetadata ( key, value) {
return function ( target) {
Reflect. defineMetadata ( key, value, target)
}
}
@classMetadata ( 'name' , 'person' )
class C {
}
如果这个装饰器需要修饰类的原型,那么需要多加参数,否则报错:
function classMetadata ( key, value) {
return function ( target, propertyName) {
Reflect. defineMetadata ( key, value, target, propertyName)
}
}
class C {
@classMetadata ( 'name' , 'person' )
hello ( ) { }
}
IOC&DI
控制反转先举个简单例子。 比如我要找个女朋友,女朋友要车和要房,没有车和没有房女朋友就不会有,于是会有这样的代码:
interface BigHouse {
}
class MyHouse implements BigHouse {
}
interface BigCar {
}
class MyCar implements BigCar {
}
class GirlFriend {
house: BigHouse
car: BigCar
constructor ( house: BigHouse, car: BigCar) {
this . car= car
this . house= house
}
start ( ) {
console . log ( 'yehuozhili女朋友创建完毕' )
}
}
let GF = new GirlFriend ( new MyHouse , new MyCar )
GF . start ( )
这里我要手动创建我的房子和车,来满足女朋友要求的大房子和大车,这样女朋友才可以成功创建。 现在觉得这个模式是不是已经很舒服了,不用优化了?其实还有更牛b的优化方式。 按上面那个举例就是,由于我单身太久,于是符合了国家分配政策,这样我可以直接领取女朋友,而女朋友所要的房子和车子,国家会来分配给她。我只要干一件事,就是领女朋友就ok。 这里就可能有个问题,本来我可以掌控我的女朋友好看或者不好看,只要满足她需求即可,但是领女朋友就不一样了,这就是控制反转,而里面的国家就是IOC里容器的概念。 IOC和DI是一个概念的不同角度描述,对于女朋友来说,她依赖国家分配的房子,那么她这种方式,就是依赖注入。 实际在nest中,我们拿到女朋友,还需要使用她,这个房子和车子是我们自己手工搭建的逻辑,可以对房子和车子进行控制,通过容器的注入整合,可以在各种女朋友上使用车和房,达到换女朋友不换车和房的效果。
结合nest
一般service中处理业务逻辑,注入其他模块中的方法就是在module的装饰器里的providers数组里加入,同时,在controller的constructor里用private声明这个service,这样这个service就可以使用了。 这个例子里面,controller是女朋友,service是车和房,module的providers里加入service就代表注册车和房依赖,而controller是女朋友,也在module的controllers数组里进行了注册,这样这个module的容器里就全了。 除了直接在providers里面直接注册service,还可以使用useClass,useValue,useFactory的形式,而useValue和useFactory是需要返回实例的。 nest里声明的priviate类型会当成注入形式的provide上面的类型,没有这个类型就会报错,如果provide想使用字符串,需要使用Inject装饰器装饰对应的未找到服务的声明。