- 依赖倒置(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: '小满哈哈哈' } }