解读 IoC 框架 InversifyJS
InversityJS 是一个 IoC 框架。IoC(Inversion of Control) 包括依赖注入(Dependency Injection) 和依赖查询(Dependency Lookup)。
相比于类继承的方式,控制反转解耦了父类和子类的联系。
案例解析
import 'reflect-metadata'
import { inject, injectable, Container } from 'inversify'
const container = new Container()
@injectable()
class PopMusic {
getName() {
return '流行音乐'
}
}
container.bind('request1').to(PopMusic)
@injectable()
class ClassicalMusic {
getName() {
return '古典音乐'
}
}
container.bind('request2').to(ClassicalMusic)
@injectable()
class Music {
pm: any
cm: any
constructor(
@inject('request1') popMusic: any,
@inject('request2') classicalMusic: any) {
this.pm = popMusic
this.cm = classicalMusic
}
getName() {
const result = this.pm.getName() + this.cm.getName()
return result
}
}
container.bind('Plan').to(Music)
const music: any = container.get('Plan')
console.log(music.getName()) // 流行音乐古典音乐
上述案例可以抽象为下图:
虚线表示可以注入,但在代码中没有表现出来。
代码流程可概括如下:
1.将所有相关类(这里指 Music、popMusic、classicMusic) 通过 @injectable
声明进 container
容器;
2.通过 container.get()
获取 container.bind().to(target)
中的目标对象(这里指 Music);
3.如果目标对象中的 constructor() 里有 @inject()
, 则将相应的实例(这里指 PopMusic 与 classicalMusic 的实例)当作构造函数的参数'注入';
inject/injectable 相关源码
inject 源码简化如下:
// 这是一个属性装饰器
function inject(serviceIdentifier) {
return function (target, targetKey) {
const metadataValue = { [targetKey]: [Metadata { key: 'inject', value: serviceIdentifier })] }
Reflect.defineMetadata('inversify:tagged_props', metadataValue, target.constructor);
}
}
injectable 源码简化如下:
// 这是一个类装饰器
function injectable() {
return function (target) {
const metadataValue = []
Reflect.defineMetadata('inversify:paramtypes', metadataValue, target)
return target
}
}
从简化版源码中可以看到 inject/injectable 最终是对 Reflect.defineMetadata()
的一个使用。可以将 metadata 看成是一种相对高效的数据结构。
reflect-metadata
InversityJS 深度结合了 reflect-metadata, reflect-metadata 在 Reflect 基础上对其 api 进行了扩展。
metadata 本质上是一个
WeakMap
对象。扩展:Map 和 WeakMap 的区别
Reflect.defineMetadata(metadataKey, metadataValue, target[, propertyKey])
简化版实现如下:
const Metadata = new WeakMap()
function defineMetadata(metadataKey, metadataValue, target, propertyKey) {
metadataMap = new Map()
metadataMap.set(metadataKey, metadataValue)
targetMetadata = new Map()
targetMetadata.set(propertyKey, metadataMap)
Metadata.set(target, targetMetadata)
}
Reflect.getOwnMetadata(metadataKey, target[, propertyKey])
简化版实现如下:
function getOwnMetadata(metadataKey, target, propertyKey) {
var targetMetadata = Metadata.get(target)
var metadataMap = targetMetadata.get(propertyKey)
return metadataMap.get(metadataKey)
}
其数据结构可表示如下:
WeakMap {
target: Map {
propertyKey: Map {
metadataKey: metadataValue
}
}
}
相关链接
作者:牧云云
出处:http://www.cnblogs.com/MuYunyun/"
本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
如果您觉得本篇博文对您有所收获,请点击右下角的 [推荐],谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构