Skip to content
On this page

依赖导致原则

  • 高层模块不依赖低层模块,两者都应该依赖其抽象;
  • 抽象不应该依赖细节,细节应该依赖于抽象
  • 简单的说:就是要求对抽象进行变成,不要对实现进行编程,这样就降低了客户与实现模块间的耦合

例子:

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

原始版本

CPU接口

java
package com.huangjiliang.design.heima.principle.demo;

public interface Cpu {

    /**
     * CPU运行
     */
    void run();

}

硬盘接口

java
package com.huangjiliang.design.heima.principle.demo;

public interface HardDisk {

    /**
     * 硬盘保存数据
     * @param data
     */
    void save(String data);

    /**
     * 硬盘获取数据
     * @return
     */
    String get();

}

内存接口

java
package com.huangjiliang.design.heima.principle.demo;

public interface Memory {

    /**
     * 内存保存数据
     */
    void save(String data);

}

IntelCpu

java
package com.huangjiliang.design.heima.principle.demo;

public class IntelCpu implements Cpu{
    @Override
    public void run() {
        System.out.println("英特CPU在运行");
    }
}

希捷硬盘

java
package com.huangjiliang.design.heima.principle.demo;

/**
 * 希捷硬盘
 */
public class XijieHardDisk implements HardDisk{
    @Override
    public void save(String data) {
        System.out.println("使用希捷硬盘存储数据:" + data);
    }

    @Override
    public String get() {
        System.out.println("希捷硬盘读取数据");
        return "希捷";
    }
}

金士顿内存条

java
package com.huangjiliang.design.heima.principle.demo;

/**
 * 金士顿内存
 */
public class KingstonMemory implements Memory{
    @Override
    public void save(String data) {
        System.out.println("金士顿内存存数数据" + data);
    }
}

聚合具体成员变量的电脑类

java
package com.huangjiliang.design.heima.principle.demo;

import lombok.AllArgsConstructor;

/**
 * 依赖具体的电脑类
 */
@AllArgsConstructor
public class ComputeOrigin {

    private XijieHardDisk xijieHardDisk;
    private IntelCpu intelCpu;
    private KingstonMemory kingstonMemory;

    /**
     * 电脑运行
     */
    public void run() {
        System.out.println("电脑运行");
        intelCpu.run();
        kingstonMemory.save("内存条数据");
        xijieHardDisk.save("硬盘保存数据");
    }

}

类图

image-20220911155111202

分析

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

  • 根据依赖倒置原则进行改进:Compute电脑类依赖各个配件的接口,而不是各个配件的具体实现类

改进版本

ComputeOrigin =》 ComputeImprove

package com.huangjiliang.design.heima.principle.demo;

import lombok.AllArgsConstructor;

/**
 * 依赖各个配件抽象的电脑类
 */
@AllArgsConstructor
public class ComputeImprove {

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

    /**
     * 电脑运行
     */
    public void run() {
        System.out.println("电脑运行");
        cpu.run();
        memory.save("内存条数据");
        hardDisk.save("硬盘保存数据");
    }

}

UML

image-20220911155825710

分析

  • 因为电脑类不是依赖配件的具体,而是依赖于抽象,所以用户组装电脑的时候可以选择抽象的具体实现类
  • 面向对象的开发很好的解决了这个问题,一般情况下的抽象变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。就是实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序于实现细节的耦合度