第一章:依赖注入基础
大家好,我是你们这门课的老朋友。今天咱们聊聊依赖注入——这个听起来有点唬人、但说白了其实很朴素的概念。
我记得刚入行那会儿,听到「依赖注入」四个字,第一反应是:这又是什么高大上的设计模式?后来踩了不少坑才明白,它其实就是一种组织代码的思维方式。嗯,今天我就用最直白的方式,把这件事讲清楚。
什么是依赖注入?
先看一个最简单的例子。假设你写了一个汽车类,它需要引擎才能跑:
class Car {
private Engine engine = new GasEngine();
void start() {
engine.run();
}
}
这段代码有什么问题?Car 自己 new 了一个引擎。说白了,它把自己跟 GasEngine 死死绑在了一起。哪天你想换成 ElectricEngine,就得改 Car 的源码。
依赖注入的做法是:我不自己造,我等着别人给我。
class Car {
private Engine engine;
// 引擎从外部传入 —— 这就是注入
Car(Engine engine) {
this.engine = engine;
}
void start() {
engine.run();
}
}
看到区别了吗?Car 不再关心引擎是怎么来的。它只知道自己需要一个 Engine,至于你给的是汽油的、电动的还是氢燃料的,它不管。这就是依赖注入的核心思想:控制反转——把创建依赖的控制权,从类内部交到外部。
一句话总结:依赖注入就是「我要什么,你给什么,我不自己造」。
为什么需要依赖注入?
你可能会问:我直接 new 一个对象,简单粗暴,为什么非要绕个弯子?
我在项目中遇到过这样一个场景:一个订单模块,里面直接 new 了数据库操作类、网络请求类、日志类。刚开始跑得挺好,后来要加单元测试,问题就来了——测试订单逻辑的时候,它真的去查数据库、真的去发网络请求。跑一次测试要等十几秒,还动不动因为网络超时而失败。
为什么会这样?因为直接 new 让代码没法被替换。你没法在测试时把数据库操作换成内存模拟,也没法把网络请求换成固定返回。
依赖注入带来的好处,我列一下:
- 解耦:类与类之间不再硬绑定,改一个不影响另一个
- 可测试性:可以轻松替换成 Mock 对象,单元测试想怎么测就怎么测
- 灵活性:换个实现只需要改一处配置,不用改业务代码
- 职责清晰:每个类只管自己的业务逻辑,创建依赖的事交给别人
一个小技巧:判断你的代码是否需要依赖注入,可以问自己一个问题——「如果我要把这个类的依赖换成另一个实现,需要改几行代码?」如果超过一行,那就有优化的空间。
手动依赖注入的痛点
好了,既然依赖注入这么好,那我手动写行不行?当然可以。我早期就是这么干的:
class App {
void start() {
Engine engine = new GasEngine();
Transmission transmission = new AutoTransmission();
Car car = new Car(engine, transmission);
car.start();
}
}
看起来还行?那如果 Car 还需要轮胎、座椅、空调、音响呢?
class App {
void start() {
Engine engine = new GasEngine();
Transmission transmission = new AutoTransmission();
Tire tire1 = new Tire();
Tire tire2 = new Tire();
Tire tire3 = new Tire();
Tire tire4 = new Tire();
Seat seat = new LeatherSeat();
AC ac = new AutoAC();
Stereo stereo = new BoseStereo();
Car car = new Car(engine, transmission,
tire1, tire2, tire3, tire4,
seat, ac, stereo);
car.start();
}
}
你想想看,这还只是一个 Car。如果你的 App 里有几十个、上百个这样的对象,手动注入会变成一场噩梦:
- 代码膨胀:一个启动类里全是 new 和构造参数,动辄几百行
- 容易出错:参数顺序搞反、漏传依赖,编译时可能不报错,运行时才崩溃
- 难以维护:改一个依赖的构造方法,所有创建它的地方都得跟着改
- 生命周期管理混乱:单例对象、作用域对象,全靠手动保证,稍不留神就内存泄漏
我曾经在一个中型项目里用手动依赖注入,结果到了后期,一个 Activity 的构造参数列表长达 12 个。每次新增一个依赖,都要改 5 个文件。那段时间我做梦都在数参数顺序。后来我发誓:超过 3 个依赖,必须上框架。
知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以看到依赖注入的演进路径:从最原始的硬编码,到手动注入,再到框架自动管理。
小结
依赖注入不是什么魔法,它就是一种让代码更干净、更好测、更好改的编程习惯。手动注入在小项目里还能凑合,一旦项目膨胀到几十个模块、上百个类,你就知道框架的好处了。
接下来的章节,我们会分别深入 Hilt 和 Koin 这两个主流框架。你会看到它们如何把今天讲的这些痛点,一个个优雅地解决掉。
记住一句话:好的架构不是设计出来的,是痛点逼出来的。依赖注入框架,就是被手动注入的痛点逼出来的产物。
公众号:蓝海资料掘金营,微信deep3321