高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
下面看一个例子来理解依赖倒转原则:组装电脑
现要组装一台电脑,需要配件cpu,硬盘,内存条。只有这些配置都有了,计算机才能正常的运行。选择cpu有很多选择,如Intel,AMD等,硬盘可以选择希捷,西数等,内存条可以选择金士顿,海盗船等。
希捷硬盘类XiJieHardDisk)
package com.lmcode.principles.DependenceInversionPrinciple;// 希捷硬盘
public class XiJieHardDisk {public void save(String data) {System.out.println("使用希捷硬盘存储数据" + data);}public String get() {System.out.println("使用希捷希捷硬盘取数据");return "数据";}
}
Intel处理器IntelCpu
package com.lmcode.principles.DependenceInversionPrinciple;// Intel处理器
public class IntelCpu {public void run() {System.out.println("使用Intel处理器");}
}
金士顿内存条KingstonMemory
package com.lmcode.principles.DependenceInversionPrinciple;// 金士顿内存条
public class KingstonMemory {public void save() {System.out.println("使用金士顿作为内存条");}
}
电脑Computer
package com.lmcode.principles.DependenceInversionPrinciple;public class Computer {private XiJieHardDisk hardDisk;private IntelCpu cpu;private KingstonMemory memory;public IntelCpu getCpu() {return cpu;}public void setCpu(IntelCpu cpu) {this.cpu = cpu;}public KingstonMemory getMemory() {return memory;}public void setMemory(KingstonMemory memory) {this.memory = memory;}public XiJieHardDisk getHardDisk() {return hardDisk;}public void setHardDisk(XiJieHardDisk hardDisk) {this.hardDisk = hardDisk;}public void run() {System.out.println("计算机工作");cpu.run();memory.save();String data = hardDisk.get();System.out.println("从硬盘中获取的数据为:" + data);}
}
测试类main用来组装电脑。
package com.lmcode.principles.DependenceInversionPrinciple;public class main {public static void main(String[] args) {// 创建组件对象XiJieHardDisk xiJieHardDisk = new XiJieHardDisk();IntelCpu intelCpu = new IntelCpu();KingstonMemory kingstonMemory = new KingstonMemory();// 创建电脑对象Computer computer = new Computer();// 组装computer.setCpu(intelCpu);computer.setHardDisk(xiJieHardDisk);computer.setMemory(kingstonMemory);// 运行computer.run();}
}
上面代码可以看到已经组装了一台电脑,但是似乎组装的电脑的cpu只能是Intel的,内存条只能是金士顿的,硬盘只能是希捷的,这对用户肯定是不友好的,用户有了机箱肯定是想按照自己的喜好,选择自己喜欢的配件。
根据依赖倒转原则进行改进:
代码我们只需要修改Computer类,让Computer类依赖抽象(各个配件的接口),而不是依赖于各个组件具体的实现类。
面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现
细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。
cpu接口,硬盘接口,内存条接口
package com.lmcode.principles.DependenceInversionPrinciplePro;//cpu接口
public interface Cpu {
// 运行cpupublic void run();
}
package com.lmcode.principles.DependenceInversionPrinciplePro;// 硬盘接口
public interface HardDisk {
// 存储数据public void save(String data);
// 获取数据public String get();
}
package com.lmcode.principles.DependenceInversionPrinciplePro;//内存条接口
public interface Memory {public void save();
}
实现类
package com.lmcode.principles.DependenceInversionPrinciplePro;// Intel处理器
public class IntelCpu implements Cpu{public void run() {System.out.println("使用Intel处理器");}
}
package com.lmcode.principles.DependenceInversionPrinciplePro;// 金士顿内存条
public class KingstonMemory implements Memory{public void save() {System.out.println("使用金士顿作为内存条");}
}
package com.lmcode.principles.DependenceInversionPrinciplePro;// 希捷硬盘
public class XiJieHardDisk implements HardDisk{public void save(String data) {System.out.println("使用希捷硬盘存储数据" + data);}public String get() {System.out.println("使用希捷硬盘取数据");return "数据";}
}
Computer
此时声明组件不能声明具体的实现类,而是父接口类型的抽象
package com.lmcode.principles.DependenceInversionPrinciplePro;public class Computer {// 声明组件不能声明具体的实现类,而是父接口类型的抽象private HardDisk hardDisk;private Cpu cpu;private Memory memory;public HardDisk getHardDisk() {return hardDisk;}public void setHardDisk(HardDisk hardDisk) {this.hardDisk = hardDisk;}public Cpu getCpu() {return cpu;}public void setCpu(Cpu cpu) {this.cpu = cpu;}public Memory getMemory() {return memory;}public void setMemory(Memory memory) {this.memory = memory;}public void run() {System.out.println("计算机工作");cpu.run();memory.save();String data = hardDisk.get();System.out.println("从硬盘中获取的数据为:" + data);}
}
main
package com.lmcode.principles.DependenceInversionPrinciplePro;public class main {public static void main(String[] args) {// 创建组件对象HardDisk hardDisk = new XiJieHardDisk();Cpu cpu = new IntelCpu();Memory memory = new KingstonMemory();// 创建电脑对象Computer computer = new Computer();// 组装computer.setCpu(cpu);computer.setHardDisk(hardDisk);computer.setMemory(memory);// 运行computer.run();}
}
此时加入需要换cpu,只需要创建一个cpu的类,实现cpu接口,然后再main中创建新的cpu然后作为参数传递