前端内参
搜索文档…
陆.1.5 依赖倒置原则

01.渣男练成记:控制反转、依赖注入

小明今年20岁上大二,喜欢漂亮女孩,经过长达半年的马拉松式追求,终于俘获了聪明美丽的女孩小羽儿的芳心。两人天天腻歪在一起,一起上自习、吃饭、看电影、甚至kiss……更多的内容少儿不宜。总之,有个女朋友的感觉太好啦,小明已经彻底离不开小羽儿。代码实现如下:
1
/**
2
* 小羽儿
3
*/
4
class XiaoYuEr {
5
constructor() {
6
this.name = "小羽儿";
7
}
8
study(){}
9
eat(){}
10
watchMovie(){}
11
kiss(){}
12
}
13
14
/**
15
* 小明
16
*/
17
class XiaoMing {
18
girlfriend = new XiaoYuEr();
19
constructor() {
20
this.name = "小明";
21
}
22
23
study() {
24
console.log(`${this.name}${this.girlfriend.name}在上自习`);
25
this.girlfriend.study();
26
}
27
eat() {
28
console.log(`${this.name}${this.girlfriend.name}在吃饭`);
29
this.girlfriend.eat();
30
}
31
watchMovie() {
32
console.log(`${this.name}${this.girlfriend.name}在看电影`);
33
this.girlfriend.watchMovie();
34
}
35
kiss() {
36
console.log(`${this.name}${this.girlfriend.name}在接吻`);
37
this.girlfriend.kiss();
38
}
39
}
40
41
let xiaoming = new XiaoMing();
42
xiaoming.study(); //>>小明和小羽儿在上自习
43
xiaoming.eat(); //>>小明和小羽儿在吃饭
44
xiaoming.watchMovie(); //>>小明和小羽儿在看电影
45
xiaoming.kiss(); //>>小明和小羽儿在接吻
Copied!
幸福的日子持续了一年,小羽儿的父母想送她去美国留学,小明万般不舍,但是无奈贫贱不能移,只能看着女朋友离自己而去。伤心了几个月,好在小明长得酷酷的又有才气,很快有个漂亮的女孩小萌的喜欢上了他。于是……
1
/**
2
* 小萌
3
*/
4
class XiaoMeng {
5
constructor() {
6
this.name = "小萌";
7
}
8
study(){}
9
eat(){}
10
watchMovie(){}
11
kiss(){}
12
}
13
14
/**
15
* 小明
16
*/
17
class XiaoMing {
18
girlfriend = new XiaoMeng(); //因为换了女朋友,小明要在心里把女友换成了小萌,
19
//里外都要换,代价是昂贵的
20
constructor() {
21
this.name = "小明";
22
}
23
24
study() {
25
console.log(`${this.name}${this.girlfriend.name}在上自习`);
26
this.girlfriend.study();
27
}
28
eat() {
29
console.log(`${this.name}${this.girlfriend.name}在吃饭`);
30
this.girlfriend.eat();
31
}
32
watchMovie() {
33
console.log(`${this.name}${this.girlfriend.name}在看电影`);
34
this.girlfriend.watchMovie();
35
}
36
kiss() {
37
console.log(`${this.name}${this.girlfriend.name}在接吻`);
38
this.girlfriend.kiss();
39
}
40
}
41
42
let xiaoming = new XiaoMing();
43
xiaoming.study(); //>>小明和小萌在上自习
44
xiaoming.eat(); //>>小明和小萌在吃饭
45
xiaoming.watchMovie(); //>>小明和小萌在看电影
46
xiaoming.kiss(); //>>小明和小萌在接吻
Copied!
有了新女友,小明很快走出了郁郁寡欢的日子。梅开二度看似美好,但其实小明没有那么爱小萌,这段恋情很快就结束了。然后某天,小明突然明白了,原来自己只是害怕孤独,需要有个大学女生陪伴自己上自习、吃饭、看电影……而已,至于具体是哪个女孩他并不特别在意。于是代码如下……
1
/**
2
* 大学女生
3
*/
4
class CollegeGirl {
5
constructor() {
6
this.name = "大学女生";
7
}
8
study(){}
9
eat(){}
10
watchMovie(){}
11
kiss(){}
12
}
13
14
class Girl1 extends CollegeGirl {
15
constructor() {
16
super();
17
this.name = "小花";
18
}
19
}
20
class Girl2 extends CollegeGirl {
21
constructor() {
22
super();
23
this.name = "小蓝";
24
}
25
}
26
class Girl3 extends CollegeGirl {
27
constructor() {
28
super();
29
this.name = "小红";
30
}
31
}
32
class Girl4 extends CollegeGirl {
33
constructor() {
34
super();
35
this.name = "小美";
36
}
37
}
38
class Girl5 extends CollegeGirl {
39
constructor() {
40
super();
41
this.name = "小丫";
42
}
43
}
44
class Girl6 extends CollegeGirl {
45
constructor() {
46
super();
47
this.name = "小晴";
48
}
49
}
50
class Girl7 extends CollegeGirl {
51
constructor() {
52
super();
53
this.name = "小珂";
54
}
55
}
56
57
/**
58
* 小明
59
*/
60
class XiaoMing {
61
constructor(collegeGirl) {
62
this.name = "小明";
63
this.girlfriend = collegeGirl;
64
}
65
66
study() {
67
console.log(`${this.name}${this.girlfriend.name}在上自习`);
68
this.girlfriend.study();
69
}
70
eat() {
71
console.log(`${this.name}${this.girlfriend.name}在吃饭`);
72
this.girlfriend.eat();
73
}
74
watchMovie() {
75
console.log(`${this.name}${this.girlfriend.name}在看电影`);
76
this.girlfriend.watchMovie();
77
}
78
kiss() {
79
console.log(`${this.name}${this.girlfriend.name}在接吻`);
80
this.girlfriend.kiss();
81
}
82
}
83
84
/**
85
* 小明祈祷老天爷让自己摆脱孤独,老天爷感其诚,每天都安排不同大学女生给他
86
*/
87
function showMeCollegeGirl() {
88
let now = new Date().getUTCDay() % 7;
89
switch (now) {
90
case 1:
91
return new Girl1();
92
case 2:
93
return new Girl2();
94
case 3:
95
return new Girl3();
96
case 4:
97
return new Girl4();
98
case 5:
99
return new Girl5();
100
case 6:
101
return new Girl6();
102
case 0:
103
return new Girl7();
104
}
105
106
}
107
108
let xiaoming = new XiaoMing(showMeCollegeGirl());//将依赖的对象注入构造函数
109
//小明每天和不同女孩一起,过起了没羞没臊的渣男生活
110
xiaoming.study();
111
xiaoming.eat();
112
xiaoming.watchMovie();
113
xiaoming.kiss();
Copied!
在编程的世界里,类A引用了某个类B,称为A“依赖”B。
上面这段代码,显示了小明从依赖具体的女孩小羽儿,转为依赖抽象的大学女生。这样之后,小明内心不用更换了女朋友的位置,因此没有心理包袱,感觉很轻松。然后第108行在构造函数里传递(注入)了具体的大学女生,这就叫做依赖(于)注入(DI,Dependency Injection)。并且小明把选择女友的这种“控制权”让渡给了老天爷(由JS引擎全局作用域的showMeCollegeGirl函数来分配女孩),这叫做控制反转(IoCInversion of Control), 通常用好莱坞原则“Don't call me ,I will call you”来比喻。
IoC 最核心的地方就是:在依赖方与被依赖方之间,也就是上文中说的小明与大学女生之间引入了第三方(也即老天爷),这个第三方统称为 IoC 容器。而IoC 容器,也就是实例化抽象类的地方。比如上面的例子,IoC容器老天爷通过生产showMeCollegeGirl函数来实例化多个大学女生。
anyway,这个渣男的例子比较丧
🤣
,但是又的确是大多数男孩的成长历程,真实得可怕。我们要相信等小明再成熟一点儿,知道自己需要什么样的女孩陪伴终身之后,就会变成暖男的
😇
好了,我们继续接着来讲依赖倒置。

02.依赖倒置

依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象,不要依赖于具体实现。简单的说就是要求针对抽象进行编程,不要对具体实现进行编程,这样就降低了与具体实现模块的耦合。
  1. 1.
    高层次模块不应该依赖低层次模块,它们都应该依赖于抽象。
  2. 2.
    抽象不应该依赖于具体,具体应该依赖于抽象。
前面小明的例子,他从依赖具体的某一个女孩,转为依赖一个更抽象的CollegeGirl类。而其他具体的女孩都继承并依赖抽象的CollegeGirl类。这种依赖关系的大变化,本来其他女孩都是被依赖的,现在反倒要依赖抽象的CollegeGirl,这体现了依赖关系的倒置。所以我们可以理解“依赖倒置”为依赖关系被改变。
“依赖倒置”是粗粒度的软件设计原则; “控制反转”是遵守依赖倒置这个原则而提出来的一种设计模式; 而“依赖注入”属于更细粒度的实现“控制反转”的手段。
这3者都是为了一个目的:代码更加的“高内聚,低耦合”。

03.何谓高层次,何谓低层次?

任何一个组织机构一定有架构的设计有职能的划分。按照职能的重要性,自然就有高低层次之分。并且,随着模块的粒度划分不同高层次与低层次模块会进行变动,也许某一模块相对于另外一模块它是低层次的,但是相对于其他模块它可能又是高层次的。
比如:公司组织架构里面,高层次有CEO、总裁、总经理,低层次依次有部门经理、职员。部门经理相对CEO来说是低层次的,部门经理相对职员来说又是高层次的。
再比如:软件分层架构里面,高层次是UI层,低层次依次有BLL(商业逻辑层),DAL(数据驱动层)。而BLL相对DAL来说是高层次的,BLL相对UI层来说又是低层次的。

04.何谓抽象?

抽象如其名字一样,是一件很抽象的事物。抽象往往是相对于具体而言的,具体也可以被称为细节,当然也被称为具象。
比如:
  1. 1.
    这是一位大学女生。大学女生是抽象,具体的小玉儿、小花等就是具体。
  2. 2.
    这是一幅画。画是抽象,而油画、素描、国画而言就是具体。
  3. 3.
    这是一件艺术品,艺术品是抽象,而画、照片、瓷器等等就是具体了。
  4. 4.
    交通工具是抽象,而公交车、单车、火车等就是具体了。
  5. 5.
    表演是抽象,而唱歌、跳舞、小品等就是具体。
上面可以知道,抽象可以是物也可以是行为。具体映射到软件开发中,抽象可以是接口或者抽象类形式。

参考文献

最近更新 1yr ago