依赖倒置原则(Dependence Inversion Principle)
High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.
依赖倒置原则有三点:
- 高层模块不应该依赖底层模块,而是依赖其抽象
- 抽象不应该依赖于细节
- 细节应该依赖抽象
在业务逻辑中,拆的不能再拆的原子逻辑就是底层模块,高层模块是由一个个原子逻辑组合而成,而两者的的依赖应该依靠抽象,两者不直接发生关系。
1class People {
2 private phone: iPhone;
3
4 buy(phone: iPhone) {
5 this.phone = phone;
6 }
7
8 call() {
9 this.phone.call();
10 }
11
12 sale() {
13 const target = this.phone;
14 this.phone = null;
15 return target;
16 }
17}
18
19class iPhone {
20 call() {
21 }
22}
23
24const tom = new People();
25tom.buy(new iPhone());
26tom.call();
27tom.sale();
在上面的代码中,People直接依赖了iPhone这个实体,创建了一个实例tom,tom买了一部iPhone,打了通电话,然后把它卖了,目前看上去没什么问题,但如果将来有一天tom想买Nokia怎么办?难道把方法buy的参数和私有属性phone的类型改成? Nokia | iPhone?如果未来想买Sony再加个Sony?这显然是不合理的,那么最好的办法就是通过interface来连接两者的依赖关系。
1class People {
2 private phone: IMobilePhone;
3
4 buy(phone: IMobilePhone) {
5 this.phone = phone;
6 }
7
8 call() {
9 this.phone.call();
10 }
11
12 sale() {
13 const target = this.phone;
14 this.phone = null;
15 return target;
16 }
17}
18
19interface IMobilePhone {
20 call: () => void
21}
22
23class iPhone implements IMobilePhone {
24 call() {
25 }
26}
27
28class Sony implements IMobilePhone {
29 call() {
30 }
31}
32
33const tom = new People();
34tom.buy(new iPhone());
35tom.buy(new Sony());
36tom.call();
37tom.sale();
现在把People原本依赖的iPhone改成interface IMobilePhone,只要某个class实现了IMobilePhone,就能buy它,这样就拆开了高层模块与底层模块,代码的可维护性大大加强,这就是第一条的含义:高层模块不应该依赖底层模块,而是依赖其抽象。
后两条也很好理解,例如在ts中abstract class或interface应该作为实现类的抽象,也就是说一个实现类应该implements一个interface或者abstract class,而不是interface来implements一个class,而后者在ts语法中是合法的。对于实体间的依赖,我们都应该使用interface或者abstract class来声明。