听起来高大上的控制反转(IOC)是什么?

大家好,我是前端西瓜哥。今天我们聊聊 IOC,很高大上的东西。

IOC,全称为 Inversion Of Control,即 控制反转

控制反转是面向对象编程中的一种设计原则,作用是降低各个模块之间的耦合度。

控制反转是思想,不是具体实现。

为什么需要控制反转?

假如 Class A 需要依赖 Class B,我们一般在 A 的构造函数中实例化 B,像这样:

1
2
3
4
5
6
class A {
  constructor() {
    this.b = new B();
  }
  // ...
}

这导致了耦合,A 对 B 的依赖,是写在 A 的实现中的。如果你要把 B 换成一个加强版的 BPlus,你就要改 A 的实现。

这时候,我们可以用控制反转。

“控制反转” 这个词怎么理解?就是将原本需要程序员手动控制的程序流程,改成通过框架来控制,从原来的程序员手工控制,改为框架控制

依赖注入(DI)

DI,英文全称 Dependency Injection,即依赖注入。

依赖注入是控制反转的一种常见实现。

依赖注入这词听起来高大上,很有噱头,实际上实现非常简单,就是将依赖的 Class 先在外面实例化好,再注入到需要它的 Class 中。

像前面的 A 和 B 的依赖关系,我们可以改成:

1
2
3
4
5
6
7
8
9
class A {
  constructor(b) {
    this.b = b;
  }
  // ...
}

const b = new B(); // 在外部实例化 B
const a = new A(b); // 依赖注入

上面是通过构造函数来注入实例对象。我们也可以额外写一个 setB 方法来注入:

1
2
3
4
5
6
7
8
9
10
11
12
class A {
  constructor() {}
  setB(b) {
    this.b = b;
  }
  // ...
}

const b = new B(); // 在外部实例化 B
const a = new A(); 
a.setB(b); // 依赖注入

使用了依赖注入的技巧后,A 和 B 就解耦了,我们可以很方便地这个 B 可以很方便地做替换,如:

1
2
const bPlus = new BPlus(); // 在外部实例化 B
const a = new A(bPlus); // 依赖注入

Nestjs 的 IOC

如果你用一些框架,它们可以把依赖注入过程做得更优雅,比如 Nestjs。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  // 通过类型,判断要进行注入哪个类
  constructor(private readonly userService: UserService) {}
  
  @Get()
  findAll() {
    // 这里我们用到了 this.userService
    // 我们代码里没写注入逻辑,但 Nestjs 帮我们注入了
    return this.userService.findAll();
  }
}

在 Nestjs 的 Controller 类中,我们只要在构造函数中声明该类,Nestjs 就能自动扫描注册的依赖列表,从中找出正确的类,并帮你实例化并注入,完全不需要你手动操作。

Nestjs 能做到这点,是利用了 TypeScript 的装饰器和 Reflect.metadata 的能力。

结尾

控制反转,是将原本需要程序员手动维护的依赖控制,反转到框架上去控制。

控制反转是原则,它的常见具体实现是依赖注入(DI)。A 依赖 B,但这个 B 是谁,我不管,我交给框架,你生成好了给我。

此外你还可以用模板设计模式或其他方式。

我是前端西瓜哥,欢迎关注我,学习更多前端知识。

文章首发于我的公众号:前端西瓜哥

本文首发于我的公众号:前端西瓜哥

听起来高大上的控制反转(IOC)是什么?

https://blog.fstars.wang/posts/what-is-ioc/

作者

前端西瓜哥

发布于

2022-09-27

更新于

2023-10-14

许可协议