依赖倒置原则要求高层与底层均依赖抽象(如接口),而非具体实现;通过依赖注入或工厂解耦对象创建,确保新增实现无需修改高层代码,且变量类型、类型检查及方法修饰符均需符合多态要求。

核心是让高层模块只依赖接口或抽象类,不碰任何具体实现类;运行时才决定调用哪个子类方法——这样换底层实现,高层代码完全不用动。
用接口定义行为契约,而非具体类
高层模块(比如订单服务)不该知道日志是打到控制台还是写进文件。它只该依赖一个 Logger 接口:
public interface Logger { void log(String msg); }
然后由底层提供不同实现:ConsoleLogger、FileLogger、SlackLogger。高层只声明 Logger logger,不 new 也不 import 具体类名。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
靠依赖注入或工厂统一管理对象创建
避免在业务代码里写 new FileLogger()——这等于把耦合写死了。正确做法是:
- Spring 项目中用 @Autowired Logger logger,配合 @Primary 或 @Qualifier("file") 指定实现
- 轻量级场景可写个 LoggerFactory,根据配置 key 返回对应实例,对外只暴露 getLogger(String type) 方法
- 所有新增实现(比如加个 CloudWatchLogger),只需注册进容器或工厂,不改一行高层逻辑
确保多态真正生效的三个关键点
光有接口不够,下面这些细节没做到,解耦就形同虚设:
- 调用方变量类型必须是接口或抽象类,不能是 FileLogger logger 这种具体类型
- 禁止在代码里出现 instanceof FileLogger 或 (FileLogger) logger ——一旦这么写,扩展新实现就得改这里
- 被重写的方法不能是 static、final 或 private,否则子类无法替换行为
结合依赖倒置原则,把抽象推得更远
不只是“高层不依赖底层”,而是“双方都依赖抽象”。例如用户服务(高层)和数据库访问(底层)都应依赖 UserRepository 接口。这样:
- 测试时可注入 MockUserRepository,不连真实数据库
- 切换 MySQL 到 MongoDB,只改 Repository 实现,Service 层零修改
- 团队可以并行开发:一方写 Service 逻辑,另一方按接口契约写 DAO
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










