一个 curdboy 的碎碎念

从依赖注入的典型代表说起

正儿八经使用 springboot 写代码也有几年时间了, 逐步从只会给变量 @autowired 到现在知道构造函数注入, set 方法注入, 从只知道 @Service 到手动注册 bean 等, 对于工具的使用逐渐熟练, 当然我一直觉得工具并不重要, 重要的是这一套思想

为什么我们需要依赖注入

老生长谈, 一个很重要的原因就是方便, 我们来演进式地看待这个问题

1.如果在没有依赖注入的框架里, 我们要使用一个依赖, 最方便的, 显然是直接 new 一个

2.但因为构造一个对象有一定的开销, 所以我们会想到常用的单例模式, 也就是在一个进程里, 该类的对象只有一个, 由此还衍生出了各种单例模式的写法, 各种用到该依赖的地方, 使用一个 getInstance()

3.因此, 在依赖注入的框架里, 会自动帮忙干这个事情, 我们再也不用写各种单例模式, 此外, 还有一个重要的点, 相比需要的时候直接 getInstance, springboot 是将依赖强制注入到变量上, 好处是他可以整理依赖关系, 在复杂的系统里, 依赖是一个无向图, 如果不进行依赖的整理, 很容易就跑出来一个死循环, 也因此, 我们在使用构造函数注入的时候, 不能既 A(B b)B(A a)

4.但是, 这个思路从一开始就是有问题的, 我们假设的是, new 一个对象会产生开销, 所以才需要依赖注入管理, 但假如 new 一个对象没有开销呢? 或者, 我们不需要 new 就能使用所需要的依赖呢?

两个点
4.1 new 一个对象没有开销, 这个只能未来的 java 给答案了
4.2 不需要 new 可以使用需要的依赖, 使用静态方法, 但静态方法又有个问题, 那就是如果要知道我这个服务和其他模块的依赖关系, 只能去看 import 语句了, 相比构造函数上看还是没那么方便的, 如果把这个锅归到 java 语法上, 那也没毛病

我们该怎么进行依赖注入

说到这个, 我会想到面向接口编程, 这也是个老生常谈, 使用接口, 一般来说是为了复用, 但是好像写了这么久的业务, 也没看到可以复用的地方?

其实没得复用是开发当下时候的直观感受, 站在时间的角度上, 其实接口是应对加需求的的利器, 一般来说业务主流程注入接口, 结合工厂模式, 就可以实现加需求不改动原有代码, 当然没有变更预期的功能, 或者说赶工期(误), 不使用接口也没问题

除了复用, 使用接口在开发中的一个典型好处是便于进行单元测试, 我们在做某个具体的类的单元测试的时候, 会想办法 mock 掉其他依赖, 如果依赖是一个 class, 那么需要借助 mock 工具, 但如果依赖是一个接口, 则可以直接传入一个 mock 实现

在重构里, 接口能发挥的作用也很大, 比方说我们有一个屎山代码, 有很多功能, 有个几千行, 我们可以有一个重构的思路

1.按照调用的地方的业务职责, 从读写的角度也好, 从面向的用户群体也好, 定义一些接口

2.再让这个几千行的类实现这几个新定义出来的接口

3.对屎山代码进行必要的切分

这样子干的心智负担是不是没那么重?

由此看来, 接口可能是语言的设计者设计来, 方便开发者进行开发的东西.