以为程序依赖于实现
图一
背景1:公司是福特和本田公司的金牌合作伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就可以实现无人驾驶,该系统可以在福特和本田车上使用,只要这两个品牌的汽车使用该系统就能实现自动驾驶。于是有人做出了分析如图一。
对于图一分析:我们定义了一个AutoSystem类,一个FordCar类,一个HondaCar类。FordCar类和HondaCar类中各有三个方法:Run(启动Car)、Turn(转弯Car)、Stop(停止Car),当然了一个汽车肯定不止这些功能,这里只要能说明问题即可。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
|
public
class
HondaCar{
public
void
Run(){
Console.WriteLine(
"本田开始启动了"
);
}
public
void
Turn(){
Console.WriteLine(
"本田开始转弯了"
);
}
public
void
Stop(){
Console.WriteLine(
"本田开始停车了"
);
}
}
public
class
FordCar{
publicvoidRun(){
Console.WriteLine(
"福特开始启动了"
);
}
publicvoidTurn(){
Console.WriteLine(
"福特开始转弯了"
);
}
publicvoidStop(){
Console.WriteLine(
"福特开始停车了"
);
}
}
public
class
AutoSystem{
public
enum
CarType{
Ford,Honda
};
private
HondaCar hcar=
new
HondaCar();
private
FordCar fcar=
new
FordCar();
private
CarType type;
public
AutoSystem(CarType type){
this
.type=type;
}
private
void
RunCar(){
if
(type==CarType.Ford){
fcar.Run();
}
else
{
hcar.Run();
}
}
private
void
TurnCar(){
if
(type==CarType.Ford){
fcar.Turn();
}
else
{
hcar.Turn();
}
}
private
void
StopCar(){
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
|
public
class
AutoSystem{
public
enum
CarType{
Ford,Honda,Bmw
};
HondaCar hcar=
new
HondaCar();
FordCarf car=
new
FordCar();
BmwCar bcar=
new
BmwCar();
private
CarType type;
public
AutoSystem(CarTypetype){
this
.type=type;
}
private
void
RunCar(){
if
(type==CarType.Ford){
fcar.Run();
}
else
if
(type==CarType.Honda){
hcar.Run();
}
else
if
(type==CarType.Bmw){
bcar.Run();
}
}
private
void
TurnCar(){
if
(type==CarType.Ford){
fcar.Turn();
}
else
if
(type==CarType.Honda){
hcar.Turn();
}
else
if
(type==CarType.Bmw){
bcar.Turn();
}
}
private
void
StopCar(){
if
(type==CarType.Ford){
fcar.Stop();
}
else
if
(type==CarType.Honda){
hcar.Stop();
}
else
if
(type==CarType.Bmw){
bcar.Stop();
}
}
}
|
分析:这会给系统增加新的相互依赖。随着时间的推移,越来越多的车种必须加入到AutoSystem中,这个“AutoSystem”模块将会被if/else语句弄得很乱,而且依赖于很多的低层模块,只要低层模块发生变动,AutoSystem就必须跟着变动,
它最终将变得僵化、脆弱。
导致上面所述问题的一个原因是,含有高层策略的模块,如AutoSystem模块,依赖于它所控制的低层的具体细节的模块(如HondaCar()和FordCar())。如果我们能够找到一种方法使AutoSystem
模块独立于它所控制的具体细节,那么我们就可以自由地复用它了。我们就可以用这个模块来生成其它的程序,使得系统能够用在需要的汽车上。OOD给我们提供了一种机制来实现这种“依赖倒置”。
图二
看图 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
|
public
interface ICar
{
void
Run();
void
Turn();
void
Stop();
}
public
class
BmwCar:ICar
{
public
void
Run()
{
Console.WriteLine(
"宝马开始启动了"
);
}
public
void
Turn()
{
Console.WriteLine(
"宝马开始转弯了"
);
}
public
void
Stop()
{
Console.WriteLine(
"宝马开始停车了"
);
}
}
public
class
FordCar:ICar
{
publicvoidRun()
{
Console.WriteLine(
"福特开始启动了"
);
}
public
void
Turn()
{
Console.WriteLine(
"福特开始转弯了"
);
}
public
void
Stop()
{
Console.WriteLine(
"福特开始停车了"
);
}
}
public
class
HondaCar:ICar
{
publicvoidRun()
{
Console.WriteLine(
"本田开始启动了"
);
}
public
void
Turn()
{
Console.WriteLine(
"本田开始转弯了"
);
}
public
void
Stop()
{
Console.WriteLine(
"本田开始停车了"
);
}
}
public
class
AutoSystem
{
private
ICar icar;
public
AutoSystem(ICar icar)
{
this
.icar=icar;
}
private
void
RunCar()
{
icar.Run();
}
private
void
TurnCar()
{
icar.Turn();
}
private
void
StopCar()
{
icar.Stop();
}
}
|
现在AutoSystem系统依赖于ICar 这个抽象,而与具体的实现细节HondaCar、FordCar、BmwCar无关,所以实现细节的变化不会影响AutoSystem。对于实现细节只要实现ICar 即可,即实现细节依赖于ICar 抽象。
总结:
A.高层次的模块不应该依赖于低层次的模块,他们(程序和实现)都应该依赖于抽象。
B.抽象不应该依赖于具体,具体应该依赖于抽象。
C.何谓倒置(个人理解)?正置:以往程序依赖于实现。倒置:实现依赖于程序【程序声明了抽象成员变量,而实现就是依赖抽象成员变量进行实现,间接就形成了实现依赖程序倒置关系】。