深入理解 Daze.js 之 IoC 容器原理

1,495 阅读3分钟

简介

Daze.js 底层通过容器的模式设计,所有功能都是基于这个容器进行构建,通过容器,我们可以实现解耦、依赖注入等功能

依赖

我们创建一个普通的类

class Example{
  // ...
}

然后再创建一个可能会被依赖的类

class Attr {
  constructor(attr1, attr2, attr3) {
    this.attr1 = attr1
    this.attr2 = attr2
    this.attr3 = attr3
  }
}

第一个类依赖了第二个类

class Example {
  constructor() {
    this.attr = new Attr(1, 2, 3)
  }
}

这种形式就是我们最常见的模式,简单的依赖关系,看起来也还ok,但是如果依赖多了呢?

class Example {
  constructor() {
    this.attr1 = new Attr1()
    this.attr2 = new Attr2()
    // ...more
  }
}

我们可以看到,每次实例化 Example 的时候都需要实例化对应依赖的对象

为了解决这个问题,有人就提出了工厂模式

工厂模式

为了实现这个功能,我们需要一个可以实例化不同依赖的工厂

class Factory {
  build(type) {
    switch(type) {
      case 'car':
        return new Car()
      case 'plane':
        return new Plane()
      default:
        return
    }
  }
}

有了这个工厂,我们就可以只修改工厂的种类就可以自动实例化不同的依赖对象了

class Example {
  constructor(attrs) {
    const factory = new Factory()
    for (const attr of attrs) {
      factory.build(attr)
    }
  }
}

// 实例化依赖 Car 和 Plane 的类
const example1 = new Example(['car', 'plane'])
// 实例化依赖 Car 的类
const example2 = new Example(['car'])

依赖注入

我们可以看到,刚刚的工厂其实只是把多个依赖转移到了对工厂的依赖,工厂内部还是需要手动增加各种以来的生产线,如何解决这个问题呢,那就是依赖注入

我们改造一下Example的类

class Example {
  construtor(attr) {
    this.attr = attr
  }
}

const car = new Car()
const example = new Example(car)

我们把内部的依赖在外部实例化然后通过构造函数或者其他方法注入到类中,这就是依赖注入,是不是很简单,理解了依赖注入后,我们就可以开始 IoC容器了

IoC 容器

不管如何,现在都是通过手动注入的方式进行以来管理,那么我们可不可以自动化管理依赖呢,我们只要声明需要注入的依赖即可,这时候 IoC 容器出现了

class Container {
  constructor() {
    this.binds = {}
    this.instances = {}
  }
  
  bind(abstract, concrete) {
    if (typeof concrete === 'function') {
      this.binds[abstract] = concrete
    } else {
      this.instances[abstract] = concrete
    }
  }
  
  make(abstract, args = []) {
    if (this.instances[abstract]) return this.instances[abstract]
    return this.binds[abstract](this, ...args)
  }
}

一个 IoC 容器就粗略的完成了,我们来试验一下它是如何工作的

// 创建容器实例
const container = new Container()

// 告诉容器需要如何实例化 example
container.bind('example', (_container, attr) => {
  return new Example(_container.make(attr))
})

// 告诉容器如何实例化 car
container.bind('car', () => {
  return new Car()
})

// 告诉容器如何实例化 plane
container.bind('plane', () => {
  return new Plane()
})

// 根据参数创建 Example 实例
container.make('example', 'car')
container.make('example', 'plane')

这个可以用来实例一种依赖的容器,只要稍加修改就可以支持多依赖管理,大家可以自己动手试试~~~~~

当然 Daze.js 容器不止这些功能, 还有自动实例化、实例标签、上下文注入等等.....

传送门:

官网:dazejs.org

项目地址: github.com/dazejs/daze