Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lib专题 - 初识 IoC 框架 InversifyJS #48

Open
kangschampagne opened this issue Mar 21, 2019 · 0 comments
Open

Lib专题 - 初识 IoC 框架 InversifyJS #48

kangschampagne opened this issue Mar 21, 2019 · 0 comments

Comments

@kangschampagne
Copy link
Owner

@kangschampagne kangschampagne commented Mar 21, 2019

前言

最近在做 IM 的项目,其中有用到 IoC 的思想进行模块的解耦,也就顺便写个文章记录一下,但是不会有真实的业务代码。

什么是 IoC ?

IoC (Inversion of Control) 即控制反转,其主要的目的就是减低代码之前的耦合程度。常见的方式有两种,依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。

其实笔者是很不喜欢技术名词的,所以我们来看图简单理解一下,控制反转其实是一种思想。IoC 对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在 IoC/DI 思想中,应用程序就变成被动的了,被动的等待 IoC 容器来创建并注入它所需要的资源了。简单理解就是借助于“第三方”实现具有依赖关系的对象之间的解耦。

image
image
image

既然 IOC 是控制反转,那么到底是哪些方面的控制被反转了呢?答案是“获得依赖对象的过程被反转了”。2004年,Martin Fowler 给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection),他的这个答案,实际上给出了实现IOC的方法:注入。
所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

简单介绍完 IoC,书归正传,一起来看看 IoC 框架 InversifyJS,并通过例子来进一步加深对上面所述思想的理解。

InversifyJS

我们拿个🌰子进行分析。为了更加清晰各种定义,这边 PO 上 Ts 代码。
依照理解分步骤:

  1. 定义 interfaces, types
  2. 定义 dependencies,使用 @Injectable@Inject 装饰器
  3. 创建和配置 Container
  4. Resolve dependencies

我们搞一个比较容易理解的例子:

  1. 定义 interfaces, types
// file interfaces.ts

export interface People {
    paly(): string;
    shoting(): string;
}

export interface Basketball {
    pass(): string;
}

export interface ShotBasketball {
    shot(): string;
}


// file types.ts

const TYPES = {
    People: Symbol.for("People"),
    Basketball: Symbol.for("Basketball"),
    ShotBasketball: Symbol.for("ShotBasketball")
};

export { TYPES };
  1. 定义 dependencies,使用 @Injectable@Inject 装饰器
import { injectable, inject } from "inversify";
import "reflect-metadata";
import { People, Basketball, ShotBasketball } from "./interfaces";
import { TYPES } from "./types";

@injectable()
class SpalDing implements Basketball {
    public hit() {
        return "hit!";
    }
}

@injectable()
class JordenShotTime implements ShotBasketball {
    public shot() {
        return "Shot Basketball!";
    }
}

@injectable()
class Jorden implements People {

    private _spalding: Basketball;
    private _jordenshottime: ShotBasketball;

    public constructor(
	    @inject(TYPES.Basketball) spalding: Basketball,
	    @inject(TYPES.ShotBasketball) jordenshottime: ShotBasketball
    ) {
        this._spalding = spalding;
        this._jordenshottime = jordenshottime;
    }

    public paly() { return this._spalding.hit(); }
    public shoting() { return this._jordenshottime.shot(); }

}

export { SpalDing, JordenShotTime, Jorden };
  1. 创建和配置 Container
// file inversify.config.ts

import { Container } from "inversify";
import { TYPES } from "./types";
import { People, Basketball, ShotBasketball } from "./interfaces";
import { Jorden, SpalDing, JordenShotTime } from "./entities";

const myContainer = new Container();
myContainer.bind<People>(TYPES.People).to(Jorden);
myContainer.bind<Basketball>(TYPES.Basketball).to(SpalDing);
myContainer.bind<ShotBasketball>(TYPES.ShotBasketball).to(JordenShotTime);

export { myContainer };
  1. Resolve dependencies
import { myContainer } from "./inversify.config";
import { TYPES } from "./types";
import { People } from "./interfaces";

const joden = myContainer.get<People>(TYPES.People);

expect(joden.paly()).eql("hit!"); // true
expect(joden.shoting()).eql("Shot Basketball!"); // true

以上就是一个简单的例子,基本的概念就是:

  1. 将所有相关类(这里指 Peopel、Basketball、ShotBasketball) 通过 @Injectable 声明进 container 容器
  2. 通过 container.get() 获取 container.bind().to(target) 中的目标对象(这里指 Peopel)
  3. 如果目标对象中的 constructor() 里有 @Inject(), 则将相应的实例(这里指 Basketball 与 ShotBasketball 的实例)当作构造函数的参数'注入'

这篇 InversifyJS 的基本应用就讲到这里,后面我们会讲到相应的简单源码解释和 reflect-metadata 。

@kangschampagne kangschampagne added WRITING and removed WRITING labels Mar 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant
You can’t perform that action at this time.