|
一、依赖倒置原则定义
依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。
面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。
二、违背原则方案
通过模拟项目经理获取工作进度的例子来说明依赖倒置原则。
类中通过Stream对代码进行了简化,我觉得Stream是java8新特性中最好用,也是最简洁的
1、项目经理
package com.guor.beanutil.principle.inversion;
import com.guor.beanutil.principle.dimit.Programmer;
import java.util.ArrayList;
import java.util.List;
public class ProjectManager {
// 姓名
private String name;
// 项目
private String project;
// 进度
private String schedule;
// 计划完成时间
private String completePlanTime;
// 项目开发人员
private static List<Programmer> programmerList;
static {
programmerList = new ArrayList<>();
programmerList.add(new Programmer(&#34;哪吒&#34;,&#34;哪吒闹海&#34;,&#34;技术选型,框架搭建&#34;,0.5,Programmer.getDate(&#34;2022-08-20&#34;)));
programmerList.add(new Programmer(&#34;妲己&#34;,&#34;哪吒闹海&#34;,&#34;前端&#34;,0.3,Programmer.getDate(&#34;2022-08-25&#34;)));
programmerList.add(new Programmer(&#34;敖丙&#34;,&#34;哪吒闹海&#34;,&#34;权限项目&#34;,0.2,Programmer.getDate(&#34;2022-08-31&#34;)));
programmerList.add(new Programmer(&#34;申公豹&#34;,&#34;哪吒闹海&#34;,&#34;管理模块&#34;,0.2,Programmer.getDate(&#34;2022-08-31&#34;)));
programmerList.add(new Programmer(&#34;二郎神&#34;,&#34;哪吒闹海&#34;,&#34;数据迁移&#34;,0.1,Programmer.getDate(&#34;2022-09-05&#34;)));
}
public static List<Programmer> getProgrammerList(){
return programmerList;
}
public static void main(String[] args) {
// 获取平均项目进度
System.out.println(AvgSchedule.getSchedule());// 0.26
// 获取最慢项目进度
System.out.println(MinSchedule.getSchedule());// 0.1
}
}
2、获取平均项目进度
package com.guor.beanutil.principle.inversion;
import com.guor.beanutil.principle.dimit.Programmer;
import com.guor.beanutil.principle.dimit.ProjectManager;
public class AvgSchedule {
/**
* 获取平均项目进度
*/
public static Double getSchedule(){
return ProjectManager.getProgrammerList().stream().mapToDouble( Programmer::getSchedule ).average().orElse(0d);
}
}
3、获取最慢项目进度
package com.guor.beanutil.principle.inversion;
import com.guor.beanutil.principle.dimit.Programmer;
import com.guor.beanutil.principle.dimit.ProjectManager;
public class MinSchedule {
/**
* 获取最慢项目进度
*/
public static Double getSchedule(){
return ProjectManager.getProgrammerList().stream().mapToDouble( Programmer::getSchedule ).min().orElse(0d);
}
}
从测试结果上看,程序没有问题,验证结果正常。
但如果程序时一成不变的,可以不考虑扩展性和可维护性,那么这么做一点毛病没有。
但是,如果程序具有很多的不确定性,或者当业务发生变化时,需要不断的调整和新增,那么这样的方式似乎不是很友好。
首先,这样的方式扩展起来很麻烦,每次扩展都需要新增接口,同时对于调用方来说需要新增调用接口的代码。其次,对于这个服务类来说,随着接口数量的增加,代码行数会不断地暴增,最后难以维护。
三、依赖倒置原则改善代码
首先上述方式不具备良好的扩展性,那么用依赖倒置、面向抽象编程的方式实现就可以解决这个问题。
首先定义获取项目进度的接口,任何一个实现类都可以实现自己的计算逻辑。
1、获取项目进度接口
package com.guor.beanutil.principle.inversion;
/**
* 获取项目进度
*/
public interface IGetSchedule {
Double getSchedule();
}
2、获取平均项目进度实现类
package com.guor.beanutil.principle.inversion;
import com.guor.beanutil.principle.dimit.Programmer;
import com.guor.beanutil.principle.dimit.ProjectManager;
public class AvgSchedule implements IGetSchedule {
/**
* 获取平均项目进度
*/
@Override
public Double getSchedule() {
return ProjectManager.getProgrammerList().stream().mapToDouble( Programmer::getSchedule ).average().orElse(0d);
}
}
3、获取最慢项目进度实现类
package com.guor.beanutil.principle.inversion;
import com.guor.beanutil.principle.dimit.Programmer;
import com.guor.beanutil.principle.dimit.ProjectManager;
public class MinSchedule implements IGetSchedule {
/**
* 获取最慢项目进度
*/
@Override
public Double getSchedule() {
return ProjectManager.getProgrammerList().stream().mapToDouble( Programmer::getSchedule ).min().orElse(0d);
}
}
4、项目经理测试类
package com.guor.beanutil.principle.inversion;
import com.guor.beanutil.principle.dimit.Programmer;
import java.util.ArrayList;
import java.util.List;
public class ProjectManager {
// 姓名
private String name;
// 项目
private String project;
// 进度
private String schedule;
// 计划完成时间
private String completePlanTime;
// 项目开发人员
private static List<Programmer> programmerList;
static {
programmerList = new ArrayList<>();
programmerList.add(new Programmer(&#34;哪吒&#34;,&#34;哪吒闹海&#34;,&#34;技术选型,框架搭建&#34;,0.5,Programmer.getDate(&#34;2022-08-20&#34;)));
programmerList.add(new Programmer(&#34;妲己&#34;,&#34;哪吒闹海&#34;,&#34;前端&#34;,0.3,Programmer.getDate(&#34;2022-08-25&#34;)));
programmerList.add(new Programmer(&#34;敖丙&#34;,&#34;哪吒闹海&#34;,&#34;权限项目&#34;,0.2,Programmer.getDate(&#34;2022-08-31&#34;)));
programmerList.add(new Programmer(&#34;申公豹&#34;,&#34;哪吒闹海&#34;,&#34;管理模块&#34;,0.2,Programmer.getDate(&#34;2022-08-31&#34;)));
programmerList.add(new Programmer(&#34;二郎神&#34;,&#34;哪吒闹海&#34;,&#34;数据迁移&#34;,0.1,Programmer.getDate(&#34;2022-09-05&#34;)));
}
public static List<Programmer> getProgrammerList(){
return programmerList;
}
public static void main(String[] args) {
ScheduleController scheduleController = new ScheduleController();
// 获取平均项目进度
Double schedule = scheduleController.getSchedule(new AvgSchedule());// 0.26
System.out.println(schedule);
// 获取最慢项目进度
schedule = scheduleController.getSchedule(new MinSchedule());// 0.1
System.out.println(schedule);
}
}
5、控制台输出

这与前面代码唯一的不同是新增了实现获取项目进度的入参new AvgSchedule()和new MinSchedule()。
在这两个计算方式作为入参后,扩展起来会非常的方便。
以这种抽象接口为基准搭建起来的框架结构会更加稳定,扩展性更好,条理更加清晰。
依赖倒置原则虽然看似简单,但如果想在实际项目开发中,将各模块、功能规划的井井有条,运用的炉火纯青、恰到好处,真的很难。反复阅读,仔细体会。
设计模式系列文章:

在这里插入图片描述 |
|