香雨站

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 76|回复: 0

Java设计模式6,依赖倒置原则

[复制链接]

1

主题

6

帖子

4

积分

新手上路

Rank: 1

积分
4
发表于 2022-9-22 16:11:12 | 显示全部楼层 |阅读模式
一、依赖倒置原则定义

依赖倒置原则(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("哪吒","哪吒闹海","技术选型,框架搭建",0.5,Programmer.getDate("2022-08-20")));
        programmerList.add(new Programmer("妲己","哪吒闹海","前端",0.3,Programmer.getDate("2022-08-25")));
        programmerList.add(new Programmer("敖丙","哪吒闹海","权限项目",0.2,Programmer.getDate("2022-08-31")));
        programmerList.add(new Programmer("申公豹","哪吒闹海","管理模块",0.2,Programmer.getDate("2022-08-31")));
        programmerList.add(new Programmer("二郎神","哪吒闹海","数据迁移",0.1,Programmer.getDate("2022-09-05")));
    }

    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("哪吒","哪吒闹海","技术选型,框架搭建",0.5,Programmer.getDate("2022-08-20")));
        programmerList.add(new Programmer("妲己","哪吒闹海","前端",0.3,Programmer.getDate("2022-08-25")));
        programmerList.add(new Programmer("敖丙","哪吒闹海","权限项目",0.2,Programmer.getDate("2022-08-31")));
        programmerList.add(new Programmer("申公豹","哪吒闹海","管理模块",0.2,Programmer.getDate("2022-08-31")));
        programmerList.add(new Programmer("二郎神","哪吒闹海","数据迁移",0.1,Programmer.getDate("2022-09-05")));
    }

    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()。
在这两个计算方式作为入参后,扩展起来会非常的方便。
以这种抽象接口为基准搭建起来的框架结构会更加稳定,扩展性更好,条理更加清晰。
依赖倒置原则虽然看似简单,但如果想在实际项目开发中,将各模块、功能规划的井井有条,运用的炉火纯青、恰到好处,真的很难。反复阅读,仔细体会。
设计模式系列文章:



在这里插入图片描述
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|香雨站

GMT+8, 2025-3-15 06:09 , Processed in 0.178275 second(s), 24 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.. 技术支持 by 巅峰设计

快速回复 返回顶部 返回列表