|
16 | 16 | // [!code focus] |
17 | 17 |
|
18 | 18 | 装饰器其实就是一个函数,它可以用在类、方法或者属性上,来扩展它们的功能。 |
19 | | - |
20 | 19 | 比如我可以用它来做日志记录、权限控制,或者缓存一些中间结果。 |
21 | | - |
22 | 20 | 它的最大优点是能把跟业务无关的代码从核心逻辑里抽离出来,这样代码更清晰简洁、也更好维护。 |
23 | 21 | ``` |
| 22 | + |
| 23 | +## 说说你对依赖注入的理解 |
| 24 | + |
| 25 | +```java |
| 26 | +// [!code focus] |
| 27 | + |
| 28 | +我理解的依赖注入,其实就是说,当一个服务需要用到其他组件的时候, |
| 29 | +它自己不负责创建这些依赖,而是由外部把这些依赖传进来。 |
| 30 | + |
| 31 | +举个例子,比如我有一个服务要用数据库对象。 |
| 32 | +如果我在服务里直接 new 一个数据库对象,那这个服务就跟这个数据库实现耦合得很死。 |
| 33 | + |
| 34 | +但如果我通过构造函数把数据库对象传进来,我就可以自由替换这个依赖, |
| 35 | +比如在写单元测试时用一个内存数据库或者 mock 对象来替代。 |
| 36 | + |
| 37 | +这样做的好处是,耦合度低、职责清晰,而且特别适合测试,能让代码更灵活、可维护性更强。 |
| 38 | +``` |
| 39 | + |
| 40 | +## 你是否自己实现过简化版的依赖注入容器 |
| 41 | + |
| 42 | +```java |
| 43 | +// [!code focus] |
| 44 | + |
| 45 | +我会先创建一个Map作为容器对象,用来保存服务的构造函数或实例。 |
| 46 | + |
| 47 | +然后提供一个register方法注册服务,一个resolve方法创建实例, |
| 48 | +resolve方法会自动查找构造函数的参数,递归地实例化依赖。 |
| 49 | +``` |
| 50 | + |
| 51 | +简化版依赖注入容器 |
| 52 | + |
| 53 | +```typescript |
| 54 | +class Container { |
| 55 | + private providers = new Map(); |
| 56 | + |
| 57 | + register(token: any, provider: any) { |
| 58 | + this.providers.set(token, provider); |
| 59 | + } |
| 60 | + |
| 61 | + resolve(token: any): any { |
| 62 | + const Provider = this.providers.get(token); |
| 63 | + const deps = Reflect.getMetadata("design:paramtypes", Provider) || []; |
| 64 | + const instances = deps.map((dep: any) => this.resolve(dep)); |
| 65 | + return new Provider(...instances); |
| 66 | + } |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +进阶版带装饰器的依赖注入容器 |
| 71 | + |
| 72 | +```typescript |
| 73 | +import "reflect-metadata"; |
| 74 | + |
| 75 | +class Container { |
| 76 | + private providers = new Map(); |
| 77 | + |
| 78 | + register(token: any) { |
| 79 | + this.providers.set(token, token); |
| 80 | + } |
| 81 | + |
| 82 | + resolve<T>(token: new (...args: any[]) => T): T { |
| 83 | + const target = this.providers.get(token); |
| 84 | + const deps = Reflect.getMetadata("design:paramtypes", target) || []; |
| 85 | + const instances = deps.map((dep: any) => this.resolve(dep)); |
| 86 | + return new target(...instances); |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +// 装饰器:用于自动注册类 |
| 91 | +function Injectable(target: any) { |
| 92 | + container.register(target); |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +```typescript |
| 97 | +const container = new Container(); |
| 98 | + |
| 99 | +@Injectable |
| 100 | +class DatabaseService {} |
| 101 | + |
| 102 | +@Injectable |
| 103 | +class UserService { |
| 104 | + constructor(private db: DatabaseService) {} |
| 105 | +} |
| 106 | + |
| 107 | +const userService = container.resolve(UserService); |
| 108 | +``` |
0 commit comments