Skip to content

FlynnLeeGit/InversifyJS

 
 

Repository files navigation

InversifyJS

Join the chat at https://gitter.im/inversify/InversifyJS Build Status Windows Build status Test Coverage npm version Dependencies img img Known Vulnerabilities Twitter Follow

NPM NPM

一个由 TypeScript 为 Javascript 和 NodeJs 运行编写的功能强大且轻量级的控制反转容器.

介绍

InversifyJS 是为 Typescript 和 Javascript 编写的一个控制反转 (IoC) 容器, 它仅有 4KB 大小, 非常的轻量. 容器通过一个类构造器来识别和注入他的依赖项.InversifyJS 的API接口非常优惠,并鼓励使用面向对象和IOC惯例进行编程. 当前文档为该项目最新版中文文档翻译,切换到(原项目页面)

初衷

JavaScript 现在已经能够很好的支持面向对象的继承特性. 这些特性设计非常有价值,但同时使用的过程中也相当的 危险.

我需要一个更好的面向对象设计方法 (面向对象设计, 合成复用原则, etc.) to protect ourselves from these threats. The problem is that OO design is difficult and that is exactly why we created InversifyJS.

InversifyJS 是一个帮助 JavaScript 开发者使用更好地方式进行面向对象程序设计的工具.

信条

InversifyJS 定制了以下四个目标:

  1. 运行 JavaScript 开发者编写遵循 SOLID 原则的代码.

  2. 促进并鼓励开发遵守Ioc设计惯例以及最佳的面向对象设计.

  3. 尽可能少的增加运行时的额外开销.

  4. 提供整套 最佳实践.

证言

Nate Kohari - Author of Ninject

"Nice work! I've taken a couple shots at creating DI frameworks for JavaScript and TypeScript, but the lack of RTTI really hinders things. The ES7 metadata gets us part of the way there (as you've discovered). Keep up the great work!"

Michel Weststrate - Author of MobX

Dependency injection like InversifyJS works nicely

安装

你可以通过 npm 来获得最新的发行版和类型定义:

$ npm install inversify reflect-metadata --save

Inversify 的 npm 包中已经包含了 InversifyJS 的类型定义.

⚠️ 提示! InversifyJS 要求 TypeScript >= 2.0 版本,并且需要在项目的 tsconfig.json 文件中对 experimentalDecorators, emitDecoratorMetadata, types and lib 编译选项进行设置

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["es6"],
        "types": ["reflect-metadata"],
        "module": "commonjs",
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}

InversifyJS 要求 JavaScript 引擎能够支持以下特性:

如果你的运行环境中有一个或多个特性无法支持,你需要通过手工导入一个 shim 或者 polyfill.

⚠️ reflect-metadata polyfill 在你的整个应用程序中仅能够被导入一次 因为反射对象是一个全局单例. 更多的详细细节可以查看 这里.

你可以在wiki查看 环境支持与集成 页面和我们提供的最佳实践案例 来了解更多.

基础入门

让我们来看一下通过 TypeScript 来调用 InversifyJS API接口的最基础用法:

步骤 1: 创建你的接口和类型

我们的目标是编写一份遵循 控制反转原则 的代码. 这意味着我们必须 "依赖于抽象接口而非依赖于实现".让我们先来进行一些接口 (抽象) 的声明 .

// 文件 interfaces.ts

interface Warrior {
    fight(): string;
    sneak(): string;
}

interface Weapon {
    hit(): string;
}

interface ThrowableWeapon {
    throw(): string;
}

InversifyJS 在运行时需要使用类型作为表示法. 我们可以使用 symbols 作为标示符, 也可以使用类或者字符串.

// 文件 types.ts

const TYPES = {
    Warrior: Symbol("Warrior"),
    Weapon: Symbol("Weapon"),
    ThrowableWeapon: Symbol("ThrowableWeapon")
};

export { TYPES };

提示: 一般来说我们建议使用 Symbols , 不过 InversifyJS 也支持使用类或者字符串字面值 (请参阅特征特征介绍部分的章节了解详细信息).

步骤 2: 通过使用 @injectable@inject 装饰器(注解)来进行依赖项声明

让我们接着来声明一些类(结构). 这些类会实现我们刚刚定义的接口,所有的类都必须使用 @injectable 装饰器进行注释.

当一个类是实现接口后, 我们还需要使用 @inject 注解去运行时的依赖.在这个例子中我们使用 Symbols Symbol("Weapon") and Symbol("ThrowableWeapon") 作为运行标识符.

// 文件 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 的文件. 这是在项目中唯一有耦合的地方. 除此之外的任何地方都不应该包含对其他类的引用!

// 文件 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: 解析依赖

你可以使用 Container 类提供的 get<T> 方法去解析依赖. 记住,你只有在编写 根目录 时才这么做 Remember that you should do this only in your 以此避免出现 服务定位器反模式.

import { myContainer } from "./inversify.config";

const ninja = myContainer.get<Warrior>(TYPES.Warrior);

expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true

正如我们所见 KatanaShuriken 已经被成功的解析和注入到 Ninja对象中.

InversifyJS 也支持没有 TypeScript 的情况下直接在 ES5 和 ES6 中运行. 转到 JavaScript 案例 to learn more!

以下是 InversifyJS 的功能以及 API 接口

让我们仔细阅读 InversifyJS 的特性!

更多详细内容请参考 wiki页面 .

生态系统

我们也在努力为开发提供更多的最佳时间方案:

更多信息请阅读 生态系统页面 .

支持

If you are experience any kind of issues we will be happy to help. You can report an issue using the issues page or the chat. You can also ask questions at Stack overflow using the inversifyjs tag.

If you want to share your thoughts with the development team or join us you will be able to do so using the official the mailing list. You can check out the wiki to learn more about InversifyJS internals.

致谢

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 under the MIT License (MIT)

Copyright © 2015-2016 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.

About

一个由 TypeScript 为 Javascript 和 NodeJs 运行编写的功能强大且轻量级的控制反转容器.(文档汉化项目)

Resources

License

Code of conduct

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors

Languages

  • TypeScript 98.4%
  • JavaScript 1.6%