栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计原则之依赖倒转原则

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计原则之依赖倒转原则

依赖倒转原则(DIP): 高层模块不应该依赖低层模块,两者都应该依赖其抽象抽象不应该依赖细节,细节应该依赖抽象。

依赖倒置原则在Java语言中的表现:

模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的
接口或抽象类不依赖于实现类
实现类依赖于接口或抽象类

更为精简的定义: 面向接口编程(Object-Oriented Design, OOD)

DIP的好处: 采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。

DIP的几种写法

接口声明依赖对象: 在接口的方法中声明依赖对象。
构造函数传递依赖对象: 在类中通过构造函数声明依赖对象(好比Spring中的构造器注入),采用构造器注入。
Setter方法传递依赖对象: 在抽象中设置Setter方法声明依赖对象(Spring中的方法注入)。

依赖倒置原则的本质: 就是通过抽象(抽象类或接口)使各个类或模块实现彼此独立,不互相影响,实现模块间的松耦合。

在项目中使用这个规则需要以下原则;

每个类尽量都要有接口或抽象类,或者抽象类和接口都有: 依赖倒置原则的基本要求,有抽象才能依赖倒置。
变量的表面类型尽量是接口或者抽象类。
任何类都不应该从具体类派生。
尽量不要重写基类已经写好的方法(里式替换原则)。
结合里式替换原则来使用: 结合里式替换原则和依赖倒置原则我们可以得出一个通俗的规则,
	 接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,
	 同时在适当的时候对父类进行细化。

一句话:依赖倒置原则的核心就是面向抽象(抽象类或者接口)编程

案例1:
未遵守依赖倒转原则

组装电脑:
现要组装一台电脑,需要配件cpu,硬盘,内存条。只有这些配置都有了,计算机才能正常的运行。选择cpu有很多选择,如Intel,AMD等,硬盘可以选择希捷,西数等,内存条可以选择金士顿,海盗船等。

类图

希捷硬盘类

public class XiJieHardDisk {

    //存储数据的方法
    public void save(String data) {
        System.out.println("使用希捷硬盘存储数据为:" + data);
    }

    //获取数据的方法
    public String get() {
        System.out.println("使用希捷硬盘取数据");
        return "数据";
    }
}

金士顿内存条类

public class KingstonMemory {

    public void save() {
        System.out.println("使用金士顿内存条");
    }
}

因特尔cup类

public class IntelCpu {

    public void run() {
        System.out.println("使用Intel处理器");
    }
}

电脑类

public class Computer {

    private XiJieHardDisk hardDisk;
    private IntelCpu cpu;
    private KingstonMemory memory;

    public XiJieHardDisk getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(XiJieHardDisk hardDisk) {
        this.hardDisk = hardDisk;
    }

    public IntelCpu getCpu() {
        return cpu;
    }

    public void setCpu(IntelCpu cpu) {
        this.cpu = cpu;
    }

    public KingstonMemory getMemory() {
        return memory;
    }

    public void setMemory(KingstonMemory memory) {
        this.memory = memory;
    }

    public void run() {
        System.out.println("运行计算机");
        String data = hardDisk.get();
        System.out.println("从硬盘上获取的数据是:" + data);
        cpu.run();
        memory.save();
    }
}

测试类(测试组装的电脑)

public class ComputerDemo {
    public static void main(String[] args) {
        //创建组件对象
        XiJieHardDisk hardDisk = new XiJieHardDisk();
        IntelCpu cpu = new IntelCpu();
        KingstonMemory memory = new KingstonMemory();

        //创建计算机对象
        Computer c = new Computer();
        //组装计算机
        c.setCpu(cpu);
        c.setHardDisk(hardDisk);
        c.setMemory(memory);

        //运行计算机
        c.run();
    }
}

测试结果

上面代码可以看到已经组装了一台电脑,但是似乎组装的电脑的cpu只能是Intel的,内存条只能是金士顿的,硬盘只能是希捷的,这对用户肯定是不友好的,用户有了机箱肯定是想按照自己的喜好,选择自己喜欢的配件。

案例2:
根据依赖倒转原则进行改进:

代码我们只需要修改Computer类,让Computer类依赖抽象(各个配件的接口),而不是依赖于各个组件具体的实现类。

类图
cpu接口

public interface Cpu {
    //运行cpu
    public void run();
}

硬盘接口

public interface HardDisk {

    //存储数据
    public void save(String data);

    //获取数据
    public String get();
}

内存条接口

public interface Memory {

    public void save();
}

英特尔CPU类(实现CPU接口)

public class IntelCpu implements Cpu {

    public void run() {
        System.out.println("使用Intel处理器");
    }
}

希捷硬盘类(实现硬盘接口)

public class XiJieHardDisk implements HardDisk {

    //存储数据的方法
    public void save(String data) {
        System.out.println("使用希捷硬盘存储数据为:" + data);
    }

    //获取数据的方法
    public String get() {
        System.out.println("使用希捷希捷硬盘取数据");
        return "数据";
    }
}

金士顿内存条类(实现内存条接口)

public class KingstonMemory implements Memory {

    public void save() {
        System.out.println("使用金士顿内存条");
    }
}

电脑类(依赖各个组件的接口)

public class Computer {

    private HardDisk hardDisk;
    private Cpu cpu;
    private Memory memory;

    public HardDisk getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(HardDisk hardDisk) {
        this.hardDisk = hardDisk;
    }

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    public Memory getMemory() {
        return memory;
    }

    public void setMemory(Memory memory) {
        this.memory = memory;
    }

    //运行计算机
    public void run() {
        System.out.println("运行计算机");
        String data = hardDisk.get();
        System.out.println("从硬盘上获取的数据是:" + data);
        cpu.run();
        memory.save();
    }
}

测试类

public class ComputerDemo {
    public static void main(String[] args) {

        //创建计算机的组件对象
        HardDisk hardDisk = new XiJieHardDisk();
        Cpu cpu = new IntelCpu();
        Memory memory = new KingstonMemory();

        //创建计算机对象
        Computer c = new Computer();
        //组装计算机
        c.setCpu(cpu);
        c.setHardDisk(hardDisk);
        c.setMemory(memory);

        //运行计算机
        c.run();
    }
}

解释说明:

面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。
即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。
当组装别的品牌组件时,只需要实现对应的接口即可。

结束!!!!!!!


					人们不愿意相信一个土匪的名字叫牧之
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/872615.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号