依赖注入(Dependency Injection,DI)是一种常用的设计模式,可以在不改变代码原有逻辑的情况下,提高应用程序的扩展性、可读性和可维护性。在 TypeScript 中,我们可以通过一些开源库实现依赖注入,如 InversifyJS、Typedi 等。本篇文章将以 InversifyJS 为例,来介绍 TypeScript 中的依赖注入。
InversifyJS 简介
InversifyJS 是一个轻量级的依赖注入容器,它提供了基于装饰器的语法来定义服务(Service)、绑定服务和解析服务。使用 InversifyJS,我们能够轻松地管理应用程序中的依赖关系,并保持代码的清晰和松耦合。
安装 InversifyJS
我们可以通过 npm 安装 InversifyJS,命令如下:
$ npm install inversify reflect-metadata
其中,reflect-metadata 是 TypeScript 的一个库,它用于在运行时反射元数据。
定义和绑定服务
定义服务是指将一个类标记为一个提供特定功能的服务。在 InversifyJS 中,我们使用 @injectable 装饰器来定义服务。例如:
import { injectable } from 'inversify'; @injectable() export class UserService { // ... }
在定义服务后,我们需要将其绑定到相应的实现类。与其它依赖注入库相似,InversifyJS 提供了很多种绑定服务的方式,这里只介绍最常用的两种:通过类和通过字符串。通过类的方式是指将类自身作为 key 绑定到实现类,如下所示:
-- -------------------- ---- ------- ------ - --------- - ---- ------------ ------ - ----------- - ---- ------------------------- ------ - -------------- - ---- -------------------------------- ----- --------- - --- ------------ -------------------------------------------- -- ----------- -------- ----------------------------------------
通过字符串的方式是指将字符串作为 key 绑定到实现类。这种方式在需要将多个实现类绑定到同一个接口时非常有用。例如:
import { Container } from 'inversify'; import { TYPES } from './types'; import { UserService } from './services/UserService'; import { MockUserService } from './services/MockUserService'; const container = new Container(); container.bind<UserService>(TYPES.UserService).to(UserService); container.bind<UserService>(TYPES.MockUserService).to(MockUserService);
在此例中,我们通过一个常量 TYPES 来定义 key,借此将两个 UserService 的实现类绑定到不同的 key 上。
解析服务
一旦我们定义和绑定了服务,就可以在其它地方解析服务并使用它了。在 InversifyJS 中,我们使用 Container 实例来解析服务。例如:
import { Container } from 'inversify'; import { TYPES } from './types'; import { UserService } from './services/UserService'; const container = new Container(); container.bind<UserService>(TYPES.UserService).to(UserService); const userService = container.get<UserService>(TYPES.UserService);
注意,我们使用 get 方法获取服务时,需要指定 key 的类型。这可以帮助 TypeScript 在编译时检查类型。
使用构造函数注入
在上面的示例中,我们使用了 get 方法来获取 UserService 实例,并传递给其它的类。但如果 UserService 有多个依赖,在这样的情况下,我们就需要手动为所有依赖项创建实例,并将它们传递给 UserService 的构造函数:
-- -------------------- ---- ------- ------ - --------- - ---- ------------ ------ - ----- - ---- ---------- ------ - ----------- - ---- ------------------------- ------ - -------------- - ---- -------------------------------- ------ - ------ - ---- ----------------- ----- --------- - --- ------------ --------------------------------------------------------------- ------------------------------------------------------------------------ ------------------------------------------------ ----- ------ - ------------------------------------ ----- -------------- - ---------------------------------------------------- ----- ----------- - --- --------------------------- --------
InversifyJS 支持构造函数注入的方式,使我们无需手动创建依赖项的实例,而是只需要将依赖项声明为构造函数的参数即可。像这样:
-- -------------------- ---- ------- ------ - --------- - ---- ------------ ------ - ----- - ---- ---------- ------ - ----------- - ---- ------------------------- ------ - -------------- - ---- -------------------------------- ------ - ------ - ---- ----------------- ------ ------------------- ------------- ------ ----- ----------- - ------------ ----------------------------- ------- -------- --------------- --------------- --------------------- ------- -------- ------- ------- - -- -
在构造函数中,我们通过 @inject 装饰器将依赖项声明为参数。然后,在使用服务时,只需要通过 Container 实例获取服务即可:
import { Container } from 'inversify'; import { TYPES } from './types'; import { UserService } from './services/UserService'; const container = new Container(); container.bind<UserService>(TYPES.UserService).to(UserService); const userService = container.get<UserService>(TYPES.UserService);
总结
正如本文所述,InversifyJS 为 TypeScript 中的依赖注入提供了方便而又灵活的解决方案。通过定义和绑定服务,我们可以使代码更加模块化,同时使用构造函数注入方式,能够轻松管理依赖关系。希望本文对 TypeScript 开发者在依赖注入方面有所帮助。
示例代码
定义服务:
import { injectable } from 'inversify'; @injectable() export class UserService { // ... }
绑定服务:
import { Container } from 'inversify'; import { UserService } from './services/UserService'; import { UserRepository } from './repositories/UserRepository'; const container = new Container(); container.bind(UserService).to(UserService); container.bind(UserRepository).toSelf();
通过字符串的方式绑定服务:
import { Container } from 'inversify'; import { TYPES } from './types'; import { UserService } from './services/UserService'; import { MockUserService } from './services/MockUserService'; const container = new Container(); container.bind<UserService>(TYPES.UserService).to(UserService); container.bind<UserService>(TYPES.MockUserService).to(MockUserService);
解析服务:
import { Container } from 'inversify'; import { TYPES } from './types'; import { UserService } from './services/UserService'; const container = new Container(); container.bind<UserService>(TYPES.UserService).to(UserService); const userService = container.get<UserService>(TYPES.UserService);
构造函数注入:
-- -------------------- ---- ------- ------ - ----------- ------ - ---- ------------ ------ - ----- - ---- ---------- ------ - -------------- - ---- -------------------------------- ------ - ------ - ---- ----------------- ------------- ------ ----- ----------- - ------------ ----------------------------- ------- -------- --------------- --------------- --------------------- ------- -------- ------- ------- - -- -
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64a7d67748841e989446e784