- 依赖倒置(Dependence Inversion Principle,DIP)是指高层模块不应该依赖底层模块,两者都应该依赖其抽象。 同时,抽象不应该依赖细节,细节应该依赖抽象。简单来说,就是依赖抽象,而不是依赖具体实现。比如Class A 依赖 Class B,这是直接依赖,如果Class A依赖 interface B,Class B也依赖interface B,这就是依赖倒置了
- 控制反转(Inversion of Control,IoC)也是一种面向对象编程的设计原则,它通过反转调用方和被调用方之间的关系,实现解耦合。 比如Class A 依赖 Class B,在A内部实例化了B。这样两个类就耦合在一起,如果是通过外部实例化B,然后在注入到A中,这样A和B就解除了耦合
- 依赖注入(Dependency Injection,DI)则是一种实现控制反转的方式,通过将被依赖对象的创建和管理由依赖方转移到外部容器(或者框架),然后将依赖的对象注入到需要使用的地方,实现解耦合。 在依赖注入中,组件不会自己创建或管理它所依赖的对象,而是由外部的组件将依赖的对象注入到它的构造函数、属性或方法中。
class A {
name: string
constructor() {
this.name = '小满'
}
}
class B {
name: string
constructor() {
this.name = new A().name
}
}
class C {
name: string
constructor() {
this.name = new A().name
}
}
如图,如果我们尝试修改A类使其name变为用户输入的值时,B类和C类都必须修改,它们是强耦合的
接下来我们用一个容器Container来统一管理依赖,Container中有两个方法provide和get用于收集和注入依赖,B类通过Container对象将依赖注入到自己身上
如图,这样一来就实现了类A和类B的解耦,即是我们所讲的“控制反转”,在这种情况下,直接修改A类将不再导致B类报错,也可以很方便地扩展其他类
完整代码:
// A类(被依赖的类)
class A {
name: string
constructor(name: string) {
this.name = name
}
}
// Container
class Container {
mo: any
constructor() {
this.mo = {}
}
// 收集依赖
provide(key: string, mo: any) {
this.mo[key] = mo
}
// 注入依赖
get(key: string) {
return this.mo[key]
}
}
const mo = new Container()
// 注册依赖
mo.provide('a', new A('小满啪啪啪'))
mo.provide('b', new A('小满哈哈哈'))
// 需要依赖A类
class B {
a: any
b: any
// 依赖注入
constructor(mo: Container) {
this.a = mo.get('a')
this.b = mo.get('b')
}
}
const b = new B(mo)
console.log(b)
B { a: A { name: '小满啪啪啪' }, b: A { name: '小满哈哈哈' } }