Open Pines-Cheng opened 3 years ago
InversifyJS 是一个 JavaScript 依赖注入库,功能强大,轻量级,使用简单。但是,将它与 React 一起作为组件特性使用仍然具有挑战性。
这是因为 inversion.js 使用构造函数注入,而 React 不允许用户扩展其组件的构造函数。因此,在 React Component 里面是获取不到 @inject 的实例的。
然而,让我们来看看几个可以用来扩展其行为的 inversion.js 扩展库。
前言
SOLID
在面向对象编程(object-oriented computer programming)中,SOLID 是五个设计原则(design principles)的缩写。
五个原则分别是:
因此,DIP:Dependency inversion principle,是面向对象编程中的设计原则之一,通过共享抽象解耦高层和低层的关系。
IoC
Inversion of control is sometimes facetiously referred to as the "Hollywood Principle: Don't call us, we'll call you".
控制反转有时被戏称为好莱坞原则: 不要打电话给我们,我们会打给你。
反转:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;
在面向对象编程中,有几个基本的方式可以实现 IoC:
所以,DI(dependency injection)是面向对象编程中 IoC 的一种实现的方式。
IoC 容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
InversifyJS 介绍
InversifyJS 是一个强大的、轻量级的 IoC 容器,使用 TS 编写,可用于构建 JS/Node 应用。InversifyJS 使用 class constructor 来定义和注入依赖,API 设计简单友好,方便你使用 OOP 和 IoC 的最佳编程实践。
JavaScript 现在支持基于类的继承的面向对象(OO)编程。这些特征是伟大的,但事实是,他们也是危险的。
我们需要一个好的 OO 设计(SOLID、复合重用(Composite Reuse)等)来保护我们自己免受这些威胁。问题是面向对象的设计是困难的,这正是我们创建 inversion.js 的原因。
InversifyJS 的开发为了实现 4 个目标:
InversifyJS 需要现代的 JavaScript engine 支持:
基础概念
Container
容器本身就是一个类实例,而 inversify 要做的就是利用这么一个类实例来管理诸多别的类实例,而且依靠一套有序的方法实现。
容器本身还有父容器和子容器的概念,所以 Container 对象有一个字段 parent 来表示,这样可以做到继承。这个概念在使用Container.resolve 的时候有用到。
Scope
在 inversify.js 中,或者说是在 IoC 的概念中存在一个叫做 scope 的单词,它是和 class 的注入关联在一起的。一个类的注入 scope可以支持以下三种模式:
Transient:每次从容器中获取的时候(也就是每次请求)都是一个新的实例 Singleton:每次从容器中获取的时候(也就是每次请求)都是同一个实例 Request:社区里也成为Scoped模式,每次请求的时候都会获取新的实例,如果在这次请求中该类被require多次,那么依然还是用同一个实例返回。
Scope可以全局配置,通过defaultScope参数传参进去,也可以针对每个类进行区别配置,使用方法是:
TS 的装饰器
参考:TS - 装饰器
Reflect Metadata
实现架构
Inversify在真正解析一个依赖之前会执行三个必须的操作(另外包含两个可选操作):
inversify的绑定过程
除了to语法,其余的语法其实都是在往Binding这个类实例的属性赋值。
就是下面这些属性:
所有的入口都是指向BindingToSyntax这个类,再往外衍生出各种when语法。
上面的所有绑定除了最后一个,都会返回一个when/on/in语法供开发者往绑定里面加入更多的元素,比如一些限制条件、指定生效scope等等,接下来的演变如下图,只有to和toDynamicValue才支持in操作,所有其走的路线是inWhenOn,其余的都是WhenOn路线:
使用
支持 Symbols
在非常大的应用程序中,使用字符串作为将由 inversionjs 注入的类型的标识符,可能会导致命名冲突。支持并推荐使用 Symbols 而不是字符串文字。
使用步骤
声明依赖的 Demo 如下,具体可以参考 Readme。
也可以使用 property injection 代替 constructor injection ,这样就不用声明构造函数。
创建和配置容器:
使用
示例
Angular
在 Angular 2+ 的版本中,控制反转与依赖注入便是基于此实现,现在,我们来实现一个简单版:
参考