1概述编辑
所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体。简单的说就是要求对抽象进行
编程,不要对实现进行编程,这样就下降了客户与实现模块间的耦合。
2意图编辑
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变更时上层也要跟着变更,这就会致使模块的复用性下降并且大大提升了开发的成本。
面向对象的开发很好的解决了这个问题,通常状况下抽象的变化几率很小,让
用户程序依赖于抽象,实现的细节也依赖于抽象。即便实现细节不断变更,只要抽象不变,客户程序就不须要变化。这大大下降了客户程序与实现细节的
耦合度。
面向过程思想的结构图:
图一
背景1:公司是福特和本田公司的金牌合做伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就能够实现无人驾驶,该系统能够在福特和本田车上使用,只要这两个品牌的汽车使用该系统就能实现自动驾驶。因而有人作出了分析如图一。
对于图一分析:咱们定义了一个AutoSystem类,一个FordCar类,一个HondaCar类。FordCar类和HondaCar类中各有三个方法:Run(启动Car)、Turn(转弯Car)、Stop(中止Car),固然了一个汽车确定不止这些功能,这里只要能说明问题便可。AutoSystem类是一个自动驾驶系统,自动操纵这两辆车。
3代码实现编辑
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
publicclassHondaCar{
publicvoidRun()
{
Console.WriteLine(
"本田开始启动了"
);
}
publicvoidTurn()
{
Console.WriteLine(
"本田开始转弯了"
);
}
publicvoidStop()
{
Console.WriteLine(
"本田开始停车了"
);
}
}
publicclassFordCar
{
publicvoidRun()
{
Console.WriteLine(
"福特开始启动了"
);
}
publicvoidTurn()
{
Console.WriteLine(
"福特开始转弯了"
);
}
publicvoidStop()
{
Console.WriteLine(
"福特开始停车了"
);
}
}
publicclassAutoSystem
{
publicenumCarType{Ford,Honda};
privateHondaCarhcar=newHondaCar();
privateFordCarfcar=newFordCar();
privateCarTypetype;
publicAutoSystem(CarTypetype)
{
this
.type=type;
}
privatevoidRunCar()
{
if
(type==CarType.Ford)
{
fcar.Run();
}
else
{
hcar.Run();
}
}
privatevoidTurnCar()
{
if
(type==CarType.Ford)
{
fcar.Turn();
}
else
{
hcar.Turn();
}
}
privatevoidStopCar()
{
if
(type==CarType.Ford)
{
fcar.Stop();
}
else
{
hcar.Stop();
}
}
}
|
代码分析:上面的程序确实可以实现针对Ford和Honda车的无人驾驶,可是软件是在不断变化的,软件的需求也在不断的变化。
背景2:公司的业务作大了,同时成为了通用、三菱、大众的金牌合做伙伴,因而公司要求该自动驾驶系统也可以安装在这3种公司生产的汽车上。因而咱们不得不变更AutoSystem:
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
45
46
47
48
49
50
51
52
53
54
55
56
57
|
publicclassAutoSystem
{
publicenumCarType{Ford,Honda,Bmw};
HondaCarhcar=newHondaCar();
FordCarfcar=newFordCar();
BmwCarbcar=newBmwCar();
privateCarTypetype;
publicAutoSystem(CarTypetype)
{
this
.type=type;
}
privatevoidRunCar()
{
if
(type==CarType.Ford)
{
fcar.Run();
}
elseif(type==CarType.Honda)
{
hcar.Run();
}
elseif(type==CarType.Bmw)
{
bcar.Run();
}
}
privatevoidTurnCar()
{
if
(type==CarType.Ford)
{
fcar.Turn();
}
elseif(type==CarType.Honda)
{
hcar.Turn();
}
elseif(type==CarType.Bmw)
{
bcar.Turn();
}
}
privatevoidStopCar()
{
if
(type==CarType.Ford)
{
fcar.Stop();
}
elseif(type==CarType.Honda)
{
hcar.Stop();
}
elseif(type==CarType.Bmw)
{
bcar.Stop();
}
}
}
|
分析:这会给系统增长新的相互依赖。随着时间的推移,愈来愈多的车种必须加入到AutoSystem中,这个“AutoSystem”模块将会被if/else语句弄得很乱,并且依赖于不少的低层模块,只要低层模块发生变更,AutoSystem就必须跟着变更,
它最终将变得僵化、脆弱。
致使上面所述问题的一个缘由是,含有高层策略的模块,如AutoSystem模块,依赖于它所控制的低层的具体细节的模块(如HondaCar()和FordCar())。若是咱们可以找到一种方法使AutoSystem
模块独立于它所控制的具体细节,那么咱们就能够自由地复用它了。咱们就能够用这个模块来生成其它的程序,使得系统可以用在须要的汽车上。OOD给咱们提供了一种机制来实现这种“依赖倒置”。
4结构图编辑
图二
看图 2中这个简单的类图。这儿有一个“AutoSystem”类,它包含一个“ICar”接口。这个“AutoSystem”类根本不依赖于“FordCar”和“HondaCar”。因此,依赖关系被“倒置”了:“AutoSystem”模块依赖于抽象,那些具体的汽车操做也依赖于相同的抽象。
因而能够添加ICar
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
publicinterfaceICar
{
voidRun();
voidTurn();
voidStop();
}
publicclassBmwCar:ICar
{
publicvoidRun()
{
Console.WriteLine(
"宝马开始启动了"
);
}
publicvoidTurn()
{
Console.WriteLine(
"宝马开始转弯了"
);
}
publicvoidStop()
{
Console.WriteLine(
"宝马开始停车了"
);
}
}
publicclassFordCar:ICar
{
publicvoidRun()
{
Console.WriteLine(
"福特开始启动了"
);
}
publicvoidTurn()
{
Console.WriteLine(
"福特开始转弯了"
);
}
publicvoidStop()
{
Console.WriteLine(
"福特开始停车了"
);
}
}
publicclassHondaCar:ICar
{
publicvoidRun()
{
Console.WriteLine(
"本田开始启动了"
);
}
publicvoidTurn()
{
Console.WriteLine(
"本田开始转弯了"
);
}
publicvoidStop()
{
Console.WriteLine(
"本田开始停车了"
);
}
}
publicclassAutoSystem
{
privateICaricar;
publicAutoSystem(ICaricar)
{
this
.icar=icar;
}
privatevoidRunCar()
{
icar.Run();
}
privatevoidTurnCar()
{
icar.Turn();
}
privatevoidStopCar()
{
icar.Stop();
}
}
|
如今AutoSystem系统依赖于ICar 这个抽象,而与具体的实现细节HondaCar、FordCar、BmwCar无关,因此实现细节的变化不会影响AutoSystem。对于实现细节只要实现ICar 便可,即实现细节依赖于ICar 抽象。
综上:
一个应用中的重要策略决定及业务模型正是在这些高层的模块中。也正是这些模型包含着应用的特性。可是,当这些模块依赖于低层模块时,低层模块的修改将会直接影响到它们,迫使它们也去改变。这种境况是荒谬的。应该是处于高
层的模块去迫使那些低层的模块发生改变。应该是处于高层的模块优先于低层的模块。不管如何高层的模块也不该依赖于低层的模块。并且,咱们想可以复用的是高层的模块。经过
子程序库的形式,咱们已经能够很好地复用低层的模块了。当高层的模块依赖于低层的模块时,这些高层模块就很难在不一样的环境中复用。可是,当那些高层
模块独立于低层模块时,它们就能很简单地被复用了。这正是位于框架设计的最核心之处的原则。
总结:依赖倒置原则
A.高层次的模块不该该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不该该依赖于具体,具体应该依赖于抽象。