依赖注入概念与优势:DI 到底是什么?
依赖注入,简称 DI,很多人第一反应就是“那不就是 Dagger 吗?”
嗯,我刚入行时也这么想。后来才发现,DI 其实是一种设计思想,Dagger、Hilt、Koin 只是工具。
说白了,DI 就是“把对象的创建权交出去”。
举个生活中的例子
你自己去超市买米做饭,这叫手动依赖。你打电话叫外卖,米和菜由商家搞定,这就是依赖注入。
你的程序也一样——类不该自己去 new 依赖,而是等着别人把依赖送进来。
为什么需要 DI?
我在项目中遇到过这样一个场景:一个网络请求模块,直接 new 了 OkHttpClient。后来要换成 Retrofit,改代码改到崩溃。
你想想看,如果依赖是外部注入的,换起来就简单多了。
DI 的核心价值在于:
- 松耦合:类不关心依赖的具体实现,只关心接口
- 可测试性:测试时可以轻松注入 Mock 对象
- 复用性:换个实现换个环境,代码不用动
- 可维护性:改一处依赖,所有地方都跟着变
记住一句话:高内聚,低耦合。DI 就是低耦合的最佳实践。
控制反转(IoC)到底怎么理解?
控制反转是 DI 的理论基础。说白了,就是“谁控制谁”的问题。
传统写法:你控制依赖的创建。DI 写法:框架或容器控制依赖的创建。
我刚开始学的时候,一直搞不清 IoC 和 DI 的区别。
后来一位前辈一句话点醒了我:“IoC 是思想,DI 是手段。”
举个例子:
// 传统写法:主动创建
public class UserService {
private Database database = new MySQLDatabase();
}
// DI 写法:被动接收
public class UserService {
private Database database;
public UserService(Database database) {
this.database = database;
}
}
看到了吗?控制权从 UserService 转移到了外部。这就是控制反转。
手动注入 vs 框架注入
很多人纠结:直接用构造方法传参不就行了?干嘛非要用 Dagger?
我来给你拆解一下。
| 对比维度 | 手动注入 | 框架注入 |
|---|---|---|
| 代码量 | 少,但重复 | 多,但一次配置 |
| 可读性 | 直接,不用猜 | 需要学习成本 |
| 可维护性 | 依赖链一长就崩 | 自动管理依赖链 |
| 学习成本 | 零 | 高(Dagger/Hilt) |
| 适用范围 | 小项目或简单模块 | 大型多模块项目 |
我个人习惯:
- 小工具类或测试辅助类,手动注入足够
- 多模块项目,尤其涉及回归测试,一定用框架注入
避坑指南:我曾经在一个 20+ 模块的项目里用手动注入,结果改一个依赖,要改十几个构造方法。后来切换到 Hilt,才解脱。
注意:框架注入不是银弹。如果你用的是 Dagger,编译时间会变长。权衡好利弊。
总结一下:
DI 不是某个框架的专利。它是一种思维方式。
记得我在重构旧项目时,把 new 对象的地方全部改成注入,测试写起来顺手多了。
你想想看,如果每个模块都能随时替换依赖,回归测试还怕什么?