使用背景
公司生产了几种核验设备(108,208,380等),每一款核验设备上面都有测温功能,对应的测温模块来源于不同厂家的不同型号,有的是串口接入的,有的是USB口接入的。在代码中进行测温并获取温度信息时:
具体的实现类:
public class TemperatureManager {
public void doUsbTemperature(){
System.out.println("USB测温模块开始工作");
}
public double getUsbTemperature(){
System.out.println("USB测温模块获取到的温度值:36.5");
return 0d;
}
public void doSerilaPortTemperature(){
System.out.println("串口测温模块开始工作");
}
public double getSerialPortTemperature(){
System.out.println("串口测温模块获取到的温度值:36.7");
return 0d;
}
}
应用层:
public class TemperatrueTest {
public static void main(String args[]) {
String type = "USB";
TemperatureManager temperatureManager = new TemperatureManager();
if(type.equals("USB")){ // todo 这里就是高层的依赖于底层实现,如果底层没有,如果再增加一种测温类型时就需要修改底层实现
temperatureManager.doUsbTemperature();
temperatureManager.getUsbTemperature();
}else if(type.equals("SerialPort")){
temperatureManager.doSerilaPortTemperature();
temperatureManager.getSerialPortTemperature();
}
}
}
高层模块(测试类)严重依赖于底层实现,如果新增加一种测温类型时需要修改实现类,这个时候使用依赖倒置的原则,可以减少这种依赖。
依赖倒置定义
1、高层模块(应用层),不应该依赖底层模块,二者都应该依赖于其抽象。
2、抽象不应该依赖细节,细节应该依赖抽象。
3、针对接口编程,不要针对实现编程, 每个类都应该继承自接口 或抽象类。
依赖倒置的优点
可以减少类间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,可降低修改程序所造成的风险。
对上面实现方法的改造:
一、定义接口:
/**
* 测温模块的抽象
*/
public interface ITemperature {
public void doTemperature(); //测温
public double getTemperature(); // 获取温度
}
二、定义实现类:
public class UsbTemperature implements ITemperature {
@Override
public void doTemperature() {
System.out.println("UsbTemperature # doTemperature()");
}
@Override
public double getTemperature() {
System.out.println("UsbTemperature # getTemperature()");
return 0;
}
}
/**
* 具体的实现类 : 串口测温模块
*/
public class SerialPortTemperature implements ITemperature{
@Override
public void doTemperature() {
System.out.println("SerialPortTemperature # doTemperature()");
}
@Override
public double getTemperature() {
System.out.println("SerialPortTemperature # doTemperature()");
return 0;
}
}
/**
* 作为应用层和底层实现的桥梁,固定不动(因为以这里依赖于接口ITemperature)
*/
public class DeviceManager {
public ITemperature temperature;
public void setTemperature(ITemperature temperature) {
this.temperature = temperature;
}
public void doTemperature(){
temperature.doTemperature();
}
public void getTemperature(){
temperature.getTemperature();
}
}
三、高层模块的调用
一般由高层模块自己去决定选择什么实现类,底层可以随意的扩展实现,而不需要修改原来的代码
public class TemperatrueTest {
public static void main(String args[]) {
//
// String type = "USB";
// TemperatureManager temperatureManager = new TemperatureManager();
// if(type.equals("USB")){ // todo 这里就是高层的依赖于底层实现,如果底层没有,如果再增加一种测温类型时就需要修改底层实现
// temperatureManager.doUsbTemperature();
// temperatureManager.getUsbTemperature();
// }else if(type.equals("SerialPort")){
// temperatureManager.doSerilaPortTemperature();
// temperatureManager.getSerialPortTemperature();
// }
// DeviceManager类是比较稳定的,DeviceManager面向接口编程
// 应用层(测试类)只需要选择具体的实现就可以
// 底层的扩展直接新增加就可以,不用修改代码
DeviceManager deviceManager = new DeviceManager();
deviceManager.setTemperature(new UsbTemperature());
deviceManager.doTemperature();deviceManager.getTemperature();
deviceManager.setTemperature(new SerialPortTemperature());
deviceManager.doTemperature();deviceManager.getTemperature();
}
}