找回密码
立即注册
搜索
发回帖 发新帖

5639

积分

0

好友

727

主题
发表于 昨天 14:03 | 查看: 16| 回复: 0

依赖注入(Dependency-Injection,DI)只是控制反转(Inversion-of-Control,IoC)的一种实现方式。IoC 还有许多更常见的实现,比如 callback、胖指针等。

这么一说应该就好理解了。为什么 Java 选择 DI 而不是 callback 或其他方式?恰恰是因为答主提到的 OOP 原教旨主义——在 Java 中定义一个 callback 的开销无异于定义一个实体 bean。所以 Java 更进一步,把 bean 抽取出来,借助 delegation、proxy 等设计模式,实现了 DI。

一个比较典型的 IoC 场景,比如 go的http服务开发,就使用了 callback 这种 IoC 设计:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello world!")
})

Go HTTP HandleFunc 回调示例代码

对于 Go 或 C++ 这类 native 语言来说,既有闭包又有函数指针,实现 IoC 的手段有很多。但 DI 恰恰是其中开销较大的一种,所以比较少见——大白话就是:可以,但没必要。

比如 go-micro 就实现了 DI:通过替换一组接口的类的构造函数,就能加载不同的类实现,从而形成它经典的插件化方案。

那对于 C/C++ 来说,最常见的头文件与库文件分离设计,其实就是最典型的 DI。只要实现同一个头文件的定义,class implementation 随时可以替换。比如我们经常能在宏、makefile 或 configure.sh 里发现这样的代码:通过判断本地平台是 Windows、macOS 还是 Linux 来加载不同的类实现,而头文件保持不变。这其实跟 Java Spring context 实现 DI 没有本质区别,只不过这种注入是在编译期发生的。

Java Spring 把 bean 的组织关系抽取到 XML 中来实现 DI。说实话,我认为相比后来抽取成注解(annotation)的方式,XML 方案才是真正把事情做对了。可惜 XML 的组织方式配置复杂度偏高,或许是为了“降低门槛”(我不太确定),才搞出了不伦不类的注解注入方式。注解本身写在代码上面,修改注解又需要重新编译,整件事情又回到了编译期,有点类似早期的 OSGi。我个人认为这是开历史的倒车。最让我不能理解的是,既然都到了代码这一层,为什么宁愿在变量声明的地方用注解,也不愿直接把变量 new 出来?

我看了其他回答,很多人说依赖注入在 Golang 或 C++ 里不重要。私以为这绝对是错误的观点。而且你提的问题本身也不够准确——应该说,依赖注入框架在 Java 中非常流行,而在其他语言中就没那么流行。

我大概猜你想说的是:Golang 或 C++ 里没有 Spring 那种 IoC 容器大杀器。Spring 框架能发展得这么好,主要得益于 Java 本身运行期强大的动态能力,尤其是反射能力——这是其他静态语言,尤其是可以直接编译成 native code 的语言所不具备的。C++ 也可以做运行期注入,但你需要把大量类相关的元数据存储在别处,在运行期调用。我之前实习过的企业就是这么搞的:想注入类,先得用专门的软件生成各种类信息和依赖关系,当时真的是一脸懵逼。

但事实上,依赖注入这个概念是很朴素的:我们只要不在类中直接引用其他类,而是在更高的层次依次创建类,并通过构造函数之类的方法注入相关依赖,就能实现类之间的解耦。这种组织代码的方式,不管在任何语言中都能起到很好的作用。只是如果没有 IoC 容器这类框架,手动管理依赖还是会很繁琐。

所有成规模的、需求经常变动,或者需要有效进行单元测试的代码,依赖注入都能极大缓解代码耦合的状况。其实很多时候我们已经用了这些技巧,只是没有意识到罢了。




上一篇:OpenSSH SSHole漏洞遭利用,超长密码绕过SSH认证
下一篇:用 AI 编程担心代码泄露?交互式编码数据才是核心资产
您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-11-14 17:19 , Processed in 0.070493 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表