依赖倒置原则(DIP)是SOLID中第四个原则,核心是高层与低层模块都应依赖抽象(接口或抽象类),而非具体实现,从而降低耦合、提升可替换性与可维护性。

在 Java 面向对象设计中实现依赖倒置原则(DIP),关键不是“避免依赖”,而是把依赖从具体类转向抽象——也就是接口或抽象类。它不追求消除依赖,而是让依赖关系更稳定、更可替换。
定义清晰的抽象层
抽象是 DIP 的起点。所有高层模块和低层模块都应围绕它协作:
- 用 interface 定义契约,只声明方法,不写实现。例如:
UserRepository接口规定了findById和save行为,但不管数据存在 MySQL 还是 Redis 中; - 当需要共享默认逻辑时,可用 abstract class,比如日志基类提供通用格式封装,子类只需实现
writeLog; - 抽象中避免引用具体类型,也不调用具体类的方法——否则就违背了“抽象不依赖细节”。
高层模块通过抽象声明依赖
业务类(如 UserService)不应直接 new 具体实现,而应通过构造函数、Setter 或字段声明依赖抽象:
- 推荐构造注入:在构造函数参数中接收
UserRepository接口,运行时由外部传入MySqlUserRepository或MockUserRepository; - 避免在类内部
new MySqlUserRepository(),这会把高层模块和数据库实现强绑定; - 字段类型、方法参数、返回值都使用接口类型,例如
public User getUser(UserRepository repo),而非具体类。
低层模块实现抽象,不被高层反向调用
具体实现类(如 MySqlUserRepository)只做一件事:实现接口规定的契约,并且不主动被高层模块 import 或实例化:
立即学习“Java免费学习笔记(深入)”;
- 它依赖
UserRepository接口,而不是反过来; - 它不包含业务逻辑,也不引用
UserService等高层类; - 新增实现(如
RedisUserRepository)只需实现同一接口,无需修改任何已有代码。
配合依赖注入容器使用更自然
手动管理依赖可行,但 Spring、Guice 等框架能自动完成绑定,进一步降低出错概率:
- 用
@Service标记UserService,用@Repository标记MySqlUserRepository; - 通过
@Autowired注入UserRepository接口,框架会在运行时选择匹配的 Bean; - 测试时可轻松替换为
@MockBean,验证业务逻辑是否与数据源解耦。


















