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

一、依赖倒置原则

1.定义

高层模块不应该依赖低层模块,两者都应该依赖其抽象;

抽象不应该依赖细节,细节应该依赖抽象。

简单的说:面向接口编程,而不是面向实现编程。通过依赖于抽象,系统可以更加灵活、易于扩展和维护。

2.代码举例

  • 接口定义
    • CpuDiskMemory 是三个接口,分别定义了 runsavegetsave 方法。
  • 实现类
    • IntelCpu 实现了 Cpu 接口。
    • ChangChengDisk 实现了 Disk 接口。
    • KingstonMemory 实现了 Memory 接口。
  • 计算机类 Computer
    • Computer 类通过 set 方法注入 CPU、硬盘和内存,使用接口作为参数类型。
  • 客户端代码 ComputerDemo
    • ComputerDemo 创建了具体的组件实例,并将它们注入到 Computer 中进行使用。
java 复制代码
public interface Cpu {
    public void run();
}

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

    //读取数据
    public String get();

}

public interface Memory {
    public void save();
}

public class IntelCpu implements Cpu{
    @Override
    public void run() {
        System.out.println("Intel的Cpu运行了");
    }
}

public class ChangChengDisk implements Disk{
    @Override
    public void save(String data) {
        System.out.println("使用长城硬盘存储数据");
    }

    @Override
    public String get() {
        System.out.println("使用长城硬盘读取数据");
        return "数据";
    }
}

public class KingstonMemory implements Memory{
    @Override
    public void save() {
        System.out.println("使用kingston的内存条");
    }
}

public class Computer {
    private Memory memory;
    private Disk disk;
    private Cpu cpu;

    public Memory getMemory() {
        return memory;
    }

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

    public Disk getDisk() {
        return disk;
    }

    public void setDisk(Disk disk) {
        this.disk = disk;
    }

    public Cpu getCpu() {
        return cpu;
    }

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

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

public class ComputerDemo {
    public static void main(String[] args) {
        Disk disk = new ChangChengDisk();
        Cpu cpu = new IntelCpu();
        Memory memory = new KingstonMemory();

        Computer computer = new Computer();
        computer.setCpu(cpu);
        computer.setDisk(disk);
        computer.setMemory(memory);

        computer.run();
    }
}

3.代码讲解

(1)Computer 类依赖于抽象(接口),而不是具体实现

  • Computer 类中,CpuDiskMemory 都是接口类型。这意味着 Computer 类并不知道具体的实现类(如 IntelCpuChangChengDiskKingstonMemory),而是依赖于这些接口。
  • 依赖倒置原则体现
    • 高层模块(Computer) 依赖于 抽象接口(Cpu、Disk、Memory) ,而不是具体实现。这使得 Computer 类与具体组件之间解耦,可以方便地替换不同的硬件实现。

(2)实现类依赖于抽象,而不是相互依赖

  • IntelCpuChangChengDiskKingstonMemory 类都实现了各自对应的接口。
  • 依赖倒置原则体现
    • 具体实现类 依赖于接口(如 CpuDiskMemory),而不是直接依赖于 Computer 类。这保证了不同的实现类可以独立发展,而不会影响到计算机系统的设计。

(3)客户端代码灵活性

  • 客户端可以自由地选择不同的硬件实现(比如替换 ChangChengDiskSamsungDisk,替换 IntelCpuAMDCpu),而无需修改 Computer 类的任何代码。
  • 依赖倒置原则体现
    • 客户端通过接口进行依赖注入,而不是直接依赖具体类。这样就可以很方便地替换不同的实现,而不会影响整体系统的功能。

4. 改进点:依赖注入方式

目前,使用的是 Setter 注入setCpusetDisksetMemory 方法)。在实际开发中,我们还有其他的 依赖注入 方式,如:

  • 构造器注入
    • 在创建 Computer 实例时,通过构造器注入所需的硬件组件,可以确保这些组件不会为空。
  • 接口注入
    • 通过接口定义注入的方法,保证 Computer 类能够灵活注入不同的组件。

5.总结

  • 高层模块(Computer 类) 依赖于 抽象(接口) ,而不是具体实现。这使得 Computer 类能够在不修改自身代码的情况下,适应不同的硬件组件。
  • 低层模块(IntelCpu、ChangChengDisk、KingstonMemory 类) 实现了对应的接口(Cpu、Disk、Memory),符合 "低层模块依赖于抽象" 的原则。
  • 灵活性与可扩展性 :这种设计模式使得系统具有很强的扩展性,能够轻松地替换不同的实现,如使用新的 AMD CPU 或 SamsungDisk,而无需修改核心 Computer 类的逻辑。
相关推荐
卡尔特斯1 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源1 小时前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole1 小时前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫2 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide2 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261352 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源2 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
晨米酱3 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
Java中文社群3 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心3 小时前
从零开始学Flink:数据源
java·大数据·后端·flink