InversifyJS一个强大又轻量的控制反转容器,提供给JavaScript 和 Node.js 应用使用,使用TypeScript编写。
InversifyJS 地址:github.com/inversify/I…
InversifyJS官网:inversify.io
InversifyJS中文文档:www.inversify.cn
简介
InversifyJS 是一个轻量的 (4KB) 控制反转容器 (IoC),可用于编写 TypeScript 和 JavaScript 应用。 它使用类构造函数去定义和注入它的依赖。InversifyJS API 很友好易懂, 鼓励对 OOP 和 IoC 最佳实践的应用.
为什么要有 InversifyJS?
JavaScript 现在支持面向对象编程,基于类的继承。 这些特性不错但事实上它们也是 危险的。 我们需要一个优秀的面向对象设计(比如 SOLID,Composite Reuse等)来保护我们避免这些威胁。然而,面向对象的设计是复杂的,所以我们创建了 InversifyJS。
InversifyJS 是一个工具,它能帮助 JavaScript 开发者,写出出色的面向对象设计的代码。
目标
InversifyJS有4个主要目标:
-
允许JavaScript开发人员编写遵循 SOLID 原则的代码。
-
促进并鼓励遵守最佳的面向对象编程和依赖注入实践。
-
尽可能少的运行时开销。
-
提供艺术编程体验和生态。
业内评价
Nate Kohari - Ninject的作者
Michel Weststrate - MobX的作者
使用 InversifyJS 的公司
安装
您可以使用npm
获得最新的版本和类型定义:
$ npm install inversify reflect-metadata --save
Inversify npm 包已经包含了 InversifyJS 的类型定义
{
"compilerOptions": {
"target": "es5",
"lib": ["es6"],
"types": ["reflect-metadata"],
"module": "commonjs",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
inversifyjs需要现代JavaScript引擎,支持以下特性
- Reflect metadata
- Map
- Promise (Only required if using provider injection)
- Proxy (Only required if using activation handlers)
如果您的运行环境不支持这些特性,您可能需要导入 shim
或 polyfill
查看维基中的开发环境 polyfills
, 还可以从基本示例中去学习.
基础部分
让我们一起看下 inversifyjs 的基本用法和 API:
步骤 1: 声明接口和类型
我们的目标是编写遵循依赖倒置原则的代码。
这意味着我们应该 ”依赖于抽象而不依赖于具体实现“ 。
让我们先声明一些接口(抽象)。
// file interfaces.ts
interface Warrior {
fight(): string;
sneak(): string;
}
interface Weapon {
hit(): string;
}
interface ThrowableWeapon {
throw(): string;
}
Inversifyjs 需要在运行时使用类型标记作为标识符。接下来将使用 Symbol
作为标识符,您也可以使用类或字符串。
// file types.ts
const TYPES = {
Warrior: Symbol.for("Warrior"),
Weapon: Symbol.for("Weapon"),
ThrowableWeapon: Symbol.for("ThrowableWeapon")
};
export { TYPES };
步骤 2: 使用 @injectable
和 @inject
装饰器声明依赖
让我们来声明一些类,实现刚刚声明接口。他们都需要使用 @injectable
装饰器去注解。
当一个类依赖于某个接口时,我们也需要使用 @inject
装饰器,来定义在运行时可用的接口标识。在这种情况下,我们将使用 Symbol
, 如 Symbol.for("Weapon")
和 Symbol.for("ThrowableWeapon")
作为运行时的标识。
// file entities.ts
import { injectable, inject } from "inversify";
import "reflect-metadata";
import { Weapon, ThrowableWeapon, Warrior } from "./interfaces"
import { TYPES } from "./types";
@injectable()
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@injectable()
class Shuriken implements ThrowableWeapon {
public throw() {
return "hit!";
}
}
@injectable()
class Ninja implements Warrior {
private _katana: Weapon;
private _shuriken: ThrowableWeapon;
public constructor(
@inject(TYPES.Weapon) katana: Weapon,
@inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); }
public sneak() { return this._shuriken.throw(); }
}
export { Ninja, Katana, Shuriken };
如果您更喜欢使用属性注入而不是构造函数注入,那就可以不用声明类的构造函数了:
@injectable()
class Ninja implements Warrior {
@inject(TYPES.Weapon) private _katana: Weapon;
@inject(TYPES.ThrowableWeapon) private _shuriken: ThrowableWeapon;
public fight() { return this._katana.hit(); }
public sneak() { return this._shuriken.throw(); }
}
步骤 3: 创建和配置容器
推荐在命名为 inversify.config.ts
的文件中创建和配置容器。这是唯一有耦合的地方。
在您项目其余部分中的类,不应该包含对其他类的引用。
// file inversify.config.ts
import { Container } from "inversify";
import { TYPES } from "./types";
import { Warrior, Weapon, ThrowableWeapon } from "./interfaces";
import { Ninja, Katana, Shuriken } from "./entities";
const myContainer = new Container();
myContainer.bind<Warrior>(TYPES.Warrior).to(Ninja);
myContainer.bind<Weapon>(TYPES.Weapon).to(Katana);
myContainer.bind<ThrowableWeapon>(TYPES.ThrowableWeapon).to(Shuriken);
export { myContainer };
步骤 4: 解析依赖
您可以使用方法 get<T>
从 Container
中获得依赖。记得您应该在根结构(尽可能靠近应用程序的入口点的位置)去解析依赖,避免服务器定位反模式。
import { myContainer } from "./inversify.config";
import { TYPES } from "./types";
import { Warrior } from "./interfaces";
const ninja = myContainer.get<Warrior>(TYPES.Warrior);
expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true
正如我们所看到的 Katana
and Shuriken
被成功的解析和注入进 Ninja
。
InversifyJS 支持 ES5 和 ES6 而且可以在没有 TypeScript 环境下使用。 前往 JavaScript 示例了解更多
InversifyJS 特性 和 API
让我们一起看看 InversifyJS 的特性!
请查阅 wiki 获取更多细节。
- 类作为标识
- Symbol作为标识
- 容器 API
- 声明容器模块
- 容器快照
- 控制依赖项的生命周期
- 声明可选依赖
- 注入常量或者动态值
- 注入类的构造器
- 注入工厂
- 自动工厂
- 注入提供者(异步工厂)
- 激活句柄
- 构造器后置装饰器
- 中间件
- 多重注入
- 标签绑定
- 创建你自己的标签装饰器
- 命名绑定
- 默认目标
- 对层次化依赖注入系统的支持
- 上下文绑定以及 @targetName
- 属性注入
- 循环依赖
- 继承
请查阅 wiki 获取更多细节。
生态
为了提供艺术般的开发体验,我们也不断努力:
- 中间件插件
- 开发工具
- 例子
请查阅 生态 wiki 页 去了解更多。
Support
如果您遇到任何问题,我们乐意帮忙。您可以使用 问题页 报告问题。
如果您想要和开发团队分享您的想法或者加入我们,您可以参加 论坛讨论。您也可以查看 wiki 来了解更多关于 InversifyJS。
Acknowledgements
Thanks a lot to all the contributors, all the developers out there using InversifyJS and all those that help us to spread the word by sharing content about InversifyJS online. Without your feedback and support this project would not be possible.
License
License under the MIT License (MIT)
Copyright © 2015-2017 Remo H. Jansen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!