依赖注入不是万能钥匙
很多人一听说依赖注入(Dependency Injection,简称DI),就觉得这是解决代码耦合的灵丹妙药,恨不得每个类都塞进容器里管理。其实,DI有它的舒适区,也有它不该插手的地方。
比如你写一个工具类,像日期格式化、字符串处理这种不依赖外部状态的函数,硬要搞个接口再注入实现,就有点杀鸡用牛刀了。这时候直接调用静态方法更清爽,也没人会说你代码写得差。
适合用依赖注入的典型场景
当你面对的是那些容易变、难测试、依赖外部资源的组件时,DI才真正派上用场。比如数据库访问、HTTP请求、日志记录这些服务,它们的行为受环境影响大,直接在类里 new 一个 HttpClient 或 DbContext,单元测试时就得连真实服务跑,既慢又不稳定。
这时候把 HttpClient 封装成接口,通过构造函数注入,测试时换一个模拟实现,立马就能脱离网络运行测试用例。
public class OrderService
{
private readonly IOrderRepository _repository;
private readonly ILogger _logger;
public OrderService(IOrderRepository repository, ILogger logger)
{
_repository = repository;
_logger = logger;
}
public void PlaceOrder(Order order)
{
_logger.Info("开始下单");
_repository.Save(order);
}
}这个例子中,OrderService 不关心具体用的是 SQL Server 还是 MongoDB,也不用管日志是写文件还是发到 Kafka。只要接口一致,替换起来毫不费力。
框架级服务天然适合注入
现代 Web 框架比如 Spring、ASP.NET Core,从一开始就设计成支持 DI 的结构。像配置项、缓存、认证服务这些全局可用的资源,通过容器统一管理,哪里需要就在哪里声明依赖,框架自动帮你填上。
你在控制器里想用 IConfiguration 读配置?直接在构造函数写上就行,不用自己去 new ConfigurationBuilder 一堆参数。这就是 DI 在基础设施层面带来的便利。
别在不该用的地方强行注入
有些对象生命周期短、创建成本低,比如 DTO、ViewModel、临时计算用的辅助类,没必要放进容器。每次请求生成几个新对象,GC 回收也快,反而比从容器里取实例更高效。
还有那种只被一个地方调用的私有组件,也没有多实现可能,硬拆成接口加注入,只会让项目文件数量翻倍,看着累,维护也麻烦。
团队协作时 DI 能减少沟通成本
多人开发同一个系统时,DI 能明确表达“我需要什么”,而不是“我自己搞定”。比如支付模块要调用风控服务,与其让每个开发者自己去查怎么初始化那个服务,不如定义好 IRiskCheckService 接口,谁要用就注入,具体实现由负责的同学配置好。
这样一来,功能边界清晰,联调也方便。测试阶段还能用 Mock 数据挡一下,不用等对方服务上线才能干活。
小项目可以先观望
如果你做的只是一个内部小工具,几万行代码,几个人维护,结构简单,那完全可以先不用 DI 容器。把依赖关系写清楚,用普通工厂模式过渡也没问题。
等到某天发现改一个日志输出要动十几个文件,或者加个新数据源到处都要修改 new 的地方,那时候再引入 DI 才是水到渠成的事。