传统方式

比如现在有三个类,其中B类和C类中需要用到A类的实例(也就是B类和C类依赖A类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A {
name:string
constructor() {
this.name = "yajue"
}
}

class B {
a:any
constructor() {
this.a = new A().name
}
}

class C {
a:any
constructor() {
this.a = new A().name
}
}

如果将A类改为

1
2
3
4
5
6
class A {
name:string
constructor(name:string) {
this.name = name
}
}

B类和C类内部就开始飘红了

说明这些类之间的耦合度较强(创建B类或C类时出现了A类本尊)

IOC方式

浅谈控制反转与依赖注入 - 知乎 (zhihu.com)

IOC

全称Inversion of Control,控制反转

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象

DI

Dependency Injection,依赖注入,其实和IOC就是一个东西

由于控制反转概念比较含糊,所以2004年大师级人物Martin Fowler又给出了一个新的名字“依赖注入”

可能IOC只容易被理解到容器控制对象这个层面,很难让人想到谁来维护对象关系

代码

Container用来收集并集中管理依赖,就是个IOC容器

当C类需要用到其他类时,构造器通过Container直接获取类的实例,就不用在C的内部创建实例了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class A {
name:string
constructor(name:string) {
this.name = name
}
}

class B {
name:string
constructor(name:string) {
this.name = name
}
}

// 我是一个容器
class Container {
mod:any
constructor() {
this.mod = {}
}

provide(key:string,mod:any) {
this.mod[key] = mod
}

get(key:string) {
return this.mod[key]
}
}

// 容器把A和B类收集起来啦
const mod = new Container()
mod.provide("a",new A("yjsp"))
mod.provide("b",new B("yajue"))

// 我和A类、B类没有直接的依赖关系
class C {
a:any
b:any
constructor(mod:Container) {
this.a = mod.get("a")
this.b = mod.get("b")
}
}

这使类们从复杂的关系中解耦,让程序可以单独拓展其他功能,也可以方便地加入其他模块,减少维护成本