TypeScript中的依赖注入:带示例的实用指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

TypeScript中的依赖注入:从理论到实践



依赖注入(DI)是一种关键的设计模式,它允许您创建灵活、可测试且可维护的应用程序。在TypeScript中,得益于强类型和装饰器的支持,实现DI变得尤为优雅。在本文中,我们将探讨如何在实际中运用TypeScript实现依赖注入,并了解为什么该模式是现代开发的基石。



什么是依赖注入,为什么需要它?



依赖注入是一种模式,其中对象从外部获取其依赖项,而不是自己创建它们。与其在类内部编写new SomeService(),不如通过构造函数或方法传递一个现成的实例。



DI的主要优势:

  • 降低耦合度 — 类不依赖于具体实现,只依赖于抽象(接口)。
  • 简化测试 — 我们可以轻松地用模拟对象或桩件替换真实服务。
  • 提高可重用性 — 无需更改使用者代码即可替换依赖项。
  • 遵循依赖反转原则(SOLID中的DIP) — 高层模块不依赖于低层模块。


在TypeScript中实现依赖注入(无需框架)



让我们从一个简单的例子开始。假设我们有一个日志记录服务和一个使用它的类。



// 没有DI - 紧密耦合class Logger {    log(message: string): void {        console.log(`[LOG]: ${message}`);    }}

class UserService { private logger: Logger;

constructor() { this.logger = new Logger(); // 问题:紧密依赖 }

createUser(name: string): void { this.logger.log(`用户已创建:${name}`); // ... 创建逻辑 }}

// 使用DI - 通过构造函数interface ILogger { log(message: string): void;}

class ConsoleLogger implements ILogger { log(message: string): void { console.log(`[控制台日志]: ${message}`); }}

class FileLogger implements ILogger { log(message: string): void { // 写入文件的逻辑 console.log(`[文件日志]: ${message}`); }}

class UserServiceWithDI { constructor(private logger: ILogger) {} // 依赖从外部注入

createUser(name: string): void { this.logger.log(`用户已创建:${name}`); }}

// 使用const consoleLogger = new ConsoleLogger();const userService = new UserServiceWithDI(consoleLogger);userService.createUser('Alice'); // [控制台日志]: 用户已创建:Alice


如您所见,现在UserServiceWithDI不知道具体使用的是哪个日志记录器。我们可以轻松地将其替换为FileLogger或用于测试的模拟对象。



高级DI:创建简单的IoC容器



当依赖项很多时,通过构造函数手动注入会变得繁琐。这时就需要IoC容器(控制反转容器)。它管理对象的创建和生命周期。



让我们在TypeScript中实现一个简单的容器:



// 依赖工厂的类型type Factory<T> = (container: Container) => T;

class Container { private factories = new Map<string, Factory<any>>(); private instances = new Map<string, any>();

// 注册依赖(每次请求时调用工厂) register<T>(name: string, factory: Factory<T>): void { this.factories.set(name, factory); }

// 注册单例(工厂只调用一次) singleton<T>(name: string, factory: Factory<T&g

博客

书籍推荐