设计模式设计原则之依赖倒置原则

112 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

简介

依赖倒置的官方定义是:

1、上层模块不应该依赖底层模块,它们都应该依赖于抽象。

2、抽象不应该依赖于细节,细节应该依赖于抽象。

咋一看,这貌似说的就是面向接口编程。我们细细学来看看。

案例

就拿我们经常使用的AI能力调用来举例。我们在开发中经常需要使用各个AI厂家的OCR识别能力来读取身份证,那我们有AI能力的厂家就多了,阿里腾讯合合商汤等等。一开始我们用大厂的阿里腾讯。

public class AlibabaOcr {
    /**
     * 读取正面
     * @return
     */
    public String readFront() {
        return "广州市公安局";
    }
    /**
     * 读取反面
     * @return
     */
    public String readBack() {
        return "12324567";
    }
}
public class TententOcr {
    /**
     * 读取正面
     * @return
     */
    public String readFront() {
        return "杭州市公安局";
    }
    /**
     * 读取反面
     * @return
     */
    public String readBack() {
        return "22324567";
    }
}
public class IdRecognize {
    public String orc() {
        AlibabaOcr alibabaOcr = new AlibabaOcr();
        return alibabaOcr.readFront();
    }
    public static void main(String[] args) {
        IdRecognize idRecognize = new IdRecognize();
        idRecognize.orc();
    }
}

没毛病,身份证顺利识别出来了。

可是有一点老板发现OCR的成本太高了,不行,挣几个钱全部交给阿里做OCR了,于是吵着叫商户去找性价比更高的厂商。商务不辱使命终于找到合合的价格比上面两个大厂便宜了不少,于是老板兴高采烈地立马给开发说:换!马上给我换!

可是我们发现要换厂商我们就要修改IdRecognize的ocr方法,这是一个业务方法,改起来还是很容易有风险的。立马暴露出来之前的设计是有缺陷的。上层IdRecognize类严重地依赖来了下层的AlibabaOcr、TententOcr这些底层的能力类。

按照咱们依赖倒置原则,咱们应该这样写:

首先,增加一个OCR能力的接口

public interface OcrAbility {
    /**
     * 读取正面
     * @return
     */
    String readFront();

    /**
     * 读取反面
     * @return
     */
    String readBack();

}

然后各个厂商的OCR能力都去实现它,比如新增的合合厂家:

public class HeheOcr implements OcrAbility{
    @Override
    public String readFront() {
        return "徐州市公安局";
    }
    @Override
    public String readBack() {
        return "234567";
    }
}

那我们的业务实现依赖下层的抽象,即依赖接口OrcAbility的抽象方法:

public class IdRecognize {

    private OcrAbility ocrAbility;

    public IdRecognize(OcrAbility ability) {
        ocrAbility = ability;
    }

    public String ocr() {
        return ocrAbility.readFront();
    }
    
    /**真实调用**/
    public static void main(String[] args) {
        IdRecognize idRecognize = new IdRecognize(new HeheOcr());
        System.out.println(idRecognize.ocr());;
    }
}

这样依赖,在真实调用方法里我们想用什么厂家就用什么厂家的能力,而不用去改orc()方法里的内容了。这里同样满足对拓展开放,对修改关闭的开闭原则。

而这里的orcAbility的指定我们是通过构造方法设置进去的,当然这里还可以通过set方法设置进去,这里就和我们Spring的依赖注入很相似了,其实Spring里的接口注入这里也是这种思想。

总结

总的来说,依赖倒置原则的本质就是通过抽象(抽象类或接口)使各个类或模块实现彼此独立,用抽象去定义需要被调用的能力,不互相影响,实现模块间的松耦合。

但是依赖倒置原则定义中的抽象不应该依赖于细节,细节应该依赖于抽象我没有get到它的含义,望哪位大佬指点迷津。