设计模式六大原则-- 依赖倒置DIP(例解从代码到系统级解耦)
Posted amongdata
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式六大原则-- 依赖倒置DIP(例解从代码到系统级解耦)相关的知识,希望对你有一定的参考价值。
原定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)
其核心思想是:要面向接口编程(IOP),而不是面向实现编程
代码级
在java中需要遵循如下原则:
1. 模块间的依赖通过抽象类或接口发生,实现类之间的依赖关系也是通过抽象类或接口产生(实现类之间不应发生直接的依赖关系),降低系统的耦合性
2. 接口或抽象不依赖于实现类,但实现类依赖接口或抽象类,实现类对系统需要的功能具体实现,提高类的内聚程度
静态:静态代码,实现类具体依赖抽象,例实现类要实现接口,则自然依赖接口类。所以DIP讲的“细节应该依赖抽象”是在代码实现上的依赖,而非实例化或运行时
动态:运行时,则是抽象方法依赖具体实现方法的处理。是一种反向依赖
未使用DIP前:
public class Bens {
public String run(){
return "this is Bens";
}
}
public class BMW {
public String run(){
return "this is BMW";
}
}
public static class Driver{
public void drive(Bens bens){
bens.run();
}
//有新汽车类型,需要重载改方法
public void drive(BMW bmw){
bmw.run();
}
public static void main(String[] arg) {
Driver driver = new Driver();
//开奔驰
driver.drive(new Bens());
//开宝马
driver.drive(new BMW());
}
}
使用DIP后:
public interface Car{
public String run();
}
public class Bens implements Car{
@Override
public String run(){
return "this is Bens";
}
}
public class BMW implements Car{
@Override
public String run(){
return "this is BMW";
}
}
public static class Driver{
//有新汽车类型,无需改动
public void drive(Car car){
car.run();
}
public static void main(String[] arg) {
Driver driver = new Driver();
//开奔驰
driver.drive(new Bens());
//开宝马
driver.drive(new BMW());
}
}
分析
核心的变化是将变更的范围缩小。新增/修改汽车类型,将原来需要修改使用类(Driver)的使用方法(drive)消除掉了。
除了这种明显的代码解构,Spring的IOC也是依赖反转的典型应用场景
模块级
这里举两个例子:一是服务接口暴露;而是领域驱动(DDD)中对领域模型的依赖。
我们先看第一个
反模式DIP
- demo-dip 作为一个spring boot的spring cloud服务
- 同时将demo-dip作为client包.jar 分发给依赖该服务的调用方使用
不完善的DIP
- client端(抽象接口)从实现中分离
- 接口的部分实现依然保留在client端,不够干净
DIP
接口定义和实现在模块层完全分离
案例二,DDD的经典分层架构为
实际上我们为了以领域模型定业务 ,采用依赖倒置原则后,使领域层和基础设施层都只依赖于由领域模型所定义的抽象接口
服务级
我们举一个使用MQ让服务依赖反转来降低耦合的案例
假如我们有一个新零售系统,其中有三个子系统
- 订单系统:负责接单
- 拣货系统:负责生成拣货单,并通知拣货人员
- 运力系统:负责创建配送单,分配配送运力
在上图架构模式下,依赖关系至上而下,订单系统强依赖拣货系统和运力系统。 一旦下游两个系统出现任何问题,上游将无法接单。
我们选择利用MQ,实现依赖反转。调整一下架构:
此时订单不再直接依赖下游系统,它终于可以放飞自我,任意接单了。相反,下游系统则要反向依赖订单消息。该模式下,订单message变为“接口”(记住DIP核心是鼓励我们面向接口编程)
最后
从系统级维度看,如果有以下的情况,都可以考虑反转依赖,降低耦合
(1)变动方是A系统,却需要BCD配合(如,数据库IP调整,各使用方需要修改配置重启)
优化:增加中间层,让各方依赖反转,如数据库IP连接问题,增加内容DNS系统
行业有个至理名言:计算机系统中没有一个问题是不能通过加一个中间层解决的
(2)需求方是A系统,改动方却在BCD
优化:系统拆分,服务重新划分。特性业务上浮,共性业务下沉。
以上是关于设计模式六大原则-- 依赖倒置DIP(例解从代码到系统级解耦)的主要内容,如果未能解决你的问题,请参考以下文章