启蒙
最近在学习 nestjs, 发现了一种比较独特的写法,不需实例化 **class** 就可以在另外一个不相干的 class 中使用
举个例子🌰:
cat.module.ts
在 cat.module.ts 中同时引入 CatsController 和 CatsService
import { CatsController } from './cat.controller';
import { CatsService } from './cat.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
cat.service.ts
在 cat.service.ts 定义 CatsService 类, 定义方法 find, 方法内输出 find 字符
export class CatsService {
async find(num: Number){
console.log("find")
}
}
cat.controller.ts
在 cat.controller.ts 中,我们并没有实例化 CatsService 类,只是用了他的类型,但是却在 findAll 中可以使用 CatsService 类中的方法
import { CatsService } from "./cat.service";
export class CatsController {
constructor(private readonly catsService: CatsService){}
findAll(){
this.catsService.find()
}
}
原理是什么呢?🧐
这是我们今天要讲的 依赖注入(Depedency Injection)
依赖注入的优势清晰易见
-
无需实例化
在CatsController中没有实例CatsService即可使用,CatsService和CatsController进行了解耦 -
可以复用
在CatsModule中的provider中可以定义多个service,仅需在CatsController引入即可
也可以在其他controller中使用同一个service
什么是依赖注入
在解释依赖注入之前,我们要先知道一个定义,控制反转 (Inverse of Control),也就是我们经常听到的 IOC
控制反转(Inversion of Control,缩写为IoC)是一种编程思想,它的主要目的是将程序中组件之间的控制关系颠倒过来。
在传统的编程模式中,每个对象都负责创建或获取它所需要的其他对象,而在IoC中,这些对象的创建和管理被转移到一个外部容器中,由容器来管理它们的生命周期并将它们注入到需要使用它们的组件中。
这样可以增强程序的灵活性、可扩展性、可维护性和可测试性。
- 来自 chatGPT3.5
通俗一点解释在传统编程中,CatsService 需要实例化才能在CatsController中使用,使用了控制反转之后,Module 就作为了一个外部容器,把CatsService注入到CatsController 中
那么依赖注入是实现控制反转思想的其中一种实现
什么是依赖注入呢?🧐
依赖注入(Dependency Injection) 是一种编程模式,它的主要目的是解耦组件之间的依赖关系。
在依赖注入中,一个对象不再负责创建或获取它所需要的其他对象,而是由外部的容器来负责将这些依赖注入进来。这样可以使得代码更加灵活、可测试和可维护。
一图胜千言
代码实现
定义两个基础类,一个 wheel 轮子类,一个Engine发动机类,他们都要被 Car 类所使用
class Wheel{
constructor(private size){
this.size = size
}
roll(){
console.log("size",this.size)
}
}
class Engine{
constructor(private speed){
this.speed = speed
}
start(){
console.log("Engine",this.speed)
}
}
传统模式
我们在
Car中引用wheel和Engine类,造成了耦合
class Car {
private wheel:Wheel
private engine:Engine
constructor(private brand){
this.wheel = new Wheel('80cm')
this.engine = new Engine('50m/s')
this.brand = brand
}
run(){
this.wheel.roll()
this.engine.start()
}
}
🚀 依赖注入
首先我们要定义 容器类 Container,存储所有引入的类
Container
class Container {
private classMap:Map<string,Object>;
constructor(){
this.classMap = new Map()
}
set(className,injectClass){
this.classMap.set(className,injectClass)
}
get(className){
return this.classMap.get(className)
}
}
修改 Car 这个类,注入 Container 类 💉
class Car {
private wheel:Wheel
private engine:Engine
private brand:string
// 注入 Container
constructor(brand,container: Container){
this.wheel = container.get("wheel") as Wheel
this.engine = container.get("engine") as Engine
this.brand = brand
}
run(){
this.wheel.roll()
this.engine.start()
}
}
把 Container 的实例注入到 Car 类
let co = new Container();
let wheel = new Wheel('80cm')
let engine = new Engine('50m/s')
co.set("wheel",wheel)
co.set("engine",engine)
let car = new Car("宝马",co)
car.run()
以后如果要修改 Wheel 的尺寸,或者改变 Engine 的尺寸,无需深入到 Car 类中去
总结
写的比较简单,实现起来也不复杂,其实就是写了一个中间件,来收集依赖,主要是为了解耦,减少维护成本
今天是周五,明天劳动节调休