六大设计原则
定义
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
高层模块主要负责复杂的业务逻辑,低层模块主要负责基本的原子操作。
高层模块本来依赖低层模块,只有依赖低层模块,才能使用低层模块的功能。那为什么说高层模块不应该依赖低层模块?不是很奇怪吗?
其实应该这样说,高层模块不应该直接依赖低层模块,而是通过抽象类或接口产生依赖关系。
场景
我们设计一台机器,生产糖的,初始的原料只有甘蔗
public class Cane {
public void toSugar() {
return "甘蔗糖";
}
}
public class Machine {
public void make(Cane cane) {
System.out.println("生产" + cane.toSugar());
}
}
public class Client {
public static void main(String[] args) {
Machine machine = new Machine();
Cane cane = new Cane();
machine.make(cane);
// 生产甘蔗糖
}
}
现在又增加一种原材料,甜菜
public class Beet {
public void toSugar() {
return "白砂糖";
}
}
因为目前这台机器只能使用甘蔗产糖,不接受甜菜这种原材料,所以我们得“修理”机器,让它接受甜菜这种材料产糖
public class Machine {
public void make(Cane cane) {
System.out.println("生产" + cane.toSugar());
}
public void make(Beet beet) {
System.out.println("生产" + beet.toSugar());
}
}
如果又增加一种原材料呢,结果还得继续“修理”机器!我们想哈,既然是产糖的机器,那它应该能接受各种具有转化为糖的原材料才是呀!OK,我们把具有转化为糖的抽象为一个接口:
public interface ISugar {
void toSugar();
}
public class Cane implements ISugar {
public void toSugar() {
return "甘蔗糖";
}
}
public class Beet implements ISugar {
public void toSugar() {
return "白砂糖";
}
}
public class Machine {
public void make(ISugar sugar) {
System.out.println("生产" + sugar.toSugar());
}
}
这样的话,这台机器就可以接受各种能转化为糖的原材料了,无论来了哪种原材料,也不用“修理”机器了。
例子中,机器属于高层模块,原材料属于低层模块,机器并没有直接依赖甘蔗或者甜菜(细节),而是依赖能转化为糖的原材料(抽象)。
这样设计的好处是,无论怎么实现或扩展低层模块,高层模块几乎不受影响,因为高层并不直接依赖低层模块具体实现。
所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。
小结
要遵守依赖倒置原则,要求我们做到:
- 低层模块尽量依赖抽象类或接口;
- 变量声明的类型尽量是抽象类或是接口;
如果真正做到了依赖倒置,那么你也应该理解面向接口编程了,加油!!