0106_依赖倒置原则
定义:高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象
场景
以人类和机器人对象为例,人类和机器人共同的动作有吃饭、行走。

IHuman接口
- 职责:人类行为接口,定义了人类的基本行为规范
public interface IHuman {
/**
* 吃饭行为
*/
void eat();
/**
* 走路行为
*/
void walk();
}
Human类
- 职责:该类实现了IHuman接口定义的基础人类行为
public class Human implements IHuman {
private int age;
private String name;
public Human(int age, String name) {
this.age = age;
this.name = name;
}
public void eat() {
System.out.println(this.name + "在吃饭");
}
public void walk() {
System.out.println(this.name + "在走路");
}
}
Robot类接口
- 职责:该类实现了IHuman接口定义的机器人行为
public class Robot implements IHuman {
private int age;
private String name;
public Robot(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public void eat() {
System.out.println("机器人" + this.name + "正在充电");
}
@Override
public void walk() {
System.out.println("机器人" + this.name + "正在移动");
}
}
反例
WrongHumanService类
- 职责:违反依赖倒置原则,直接依赖具体实现类,而不是抽象接口
public class WrongHumanService {
// 直接依赖具体实现类 Human,违反了依赖倒置原则
private Human human;
// 如果要支持机器人,就需要增加新的属性
private Robot robot;
// 直接依赖具体实现
public WrongHumanService(Human human) {
this.human = human;
}
public WrongHumanService(Robot robot) {
this.robot = robot;
}
public void dailyRoutine() {
human.eat();
human.walk();
}
// 如果要支持机器人,需要添加新的方法
public void robotRoutine() {
robot.eat();
robot.walk();
}
}
在反例中,如果要支持多种实现,需要编写大量重复代码这种实现方式违背了依赖倒置原则,使得系统僵化、难以维护和扩展。。
正例
HumanService类
- 职责:人类服务类,该类依赖于IHuman抽象接口,而不是具体的Human实现类
public class HumanService {
// 声明对IHuman接口的依赖,不依赖具体实现类
private IHuman human;
// 通过构造函数注入依赖,确保对象创建时就具备完整功能
public HumanService(IHuman human) {
this.human = human;
}
// 通过setter方法注入依赖,提供运行时动态替换依赖的能力
public void setHuman(IHuman human) {
this.human = human;
}
// 执行日常行为,调用依赖接口的方法
public void dailyRoutine() {
human.eat(); // 调用吃饭行为
human.walk(); // 调用走路行为
}
}
Application类
- 职责:应用程序入口,演示依赖倒置原则的使用
public class Application {
public static void main(String[] args) {
IHuman human = new Human(25, "张三");
HumanService service = new HumanService(human);
service.dailyRoutine();
// 可以轻松替换为机器人
IHuman robot = new Robot(1, "机器人");
service.setHuman(robot);
service.dailyRoutine();
}
}
- 解耦合:HumanService 不直接依赖 Human 类,而是依赖 IHuman 接口
- 可扩展性:可以轻松添加新的 IHuman 实现(如 Robot)而不需要修改现有代码
总结
| 方面 | 反例(违反DIP) | 正例(遵循DIP) |
|---|---|---|
| 依赖关系 | 高层模块(Service)依赖低层模块(Human) |
双方都依赖抽象(IHuman) |
| 耦合度 | 紧耦合,Service与Human强绑定 |
松耦合,Service与具体实现无关 |
| 扩展性 | 差,增加新实现需修改Service内部 |
极佳,增加新实现只需实现接口,Service无需改动 |
| 维护性 | 低,一处改动可能引发多处连锁修改 | 高,代码稳定,修改的影响被隔离 |
| 可读性 | 较低,存在重复代码,逻辑分散 | 较高,代码简洁,意图清晰 |
| 可测试性 | 较差,难以隔离测试 | 极佳,易于注入Mock对象进行单元测试 |
核心要义:依赖倒置原则通过引入一个抽象接口层,将“策略”与“细节”分离,反转了传统的自上而下的依赖关系,使得软件架构能够更好地应对变化。针对接口编程,而不是针对实现编程,是实践这一原则的关键。

浙公网安备 33010602011771号