想讨论一下阿里开源的 Go 的 IoC 框架以及 Go 是不是真的需要 ioc

2022-06-28 10:33:21 +08:00
 Sunxy88

本人之前写 Java ,目前是 Go 语言新手。

前不久阿里开源了一款 Go 的 IoC 框架,由此引发我的好奇。搜索了一下发现 Go 还存在挺多 IoC 框架的。 只是作为新手有点好奇,面向过程语言真的需要 IoC 吗?

我理解是 Java 有 Spring 是因为它是纯面向对象的,没有函数这个概念只有方法,所以在一些需要函数的地方就需要通过 IoC 来注入一个单例。我作为使用者感觉到的是,IoC 是面向对象语言对于一些无状态的逻辑的妥协。

但是像 Go 这种面向过程的,不是就直接调用那个函数就好了吗?真的需要将 Go 写成 Java 的样子吗?

还请各位指点一下新人,提前感谢!

8004 次点击
所在节点    Go 编程语言
55 条回复
swulling
2022-06-28 13:34:40 +08:00
阿里这个框架我看了,因为 go 的语言限制大量采用了代码生成。而我对代码生成是持怀疑态度的,这里面真有问题 debug 会非常复杂。
THESDZ
2022-06-28 13:41:30 +08:00
我觉得多用 接口+实现类的方式即可,类似于 database/sql 可以在实现里面去注册到 database/sql 中,通过引入不同的实现类即可切换。

至于楼上说反射的,我觉得不见得对,起码要我来实现 ioc 的话,也是通过定义 interface+init()方法初始化来做。
Abirdcfly
2022-06-28 13:44:08 +08:00
golang 里哪个大一些,知名的项目在用 IOC 么?我目前还没用到,想学习一下。😂
frozenshadow
2022-06-28 13:46:27 +08:00
@xhinliang 如果是为了测试和解耦的话,我理解 golang 的 interface 类型是不是就可以满足。
cheng6563
2022-06-28 13:49:29 +08:00
go 语言本身做不到 IoC 自动装配,要硬上 IoC 就得用代码生成器,但代码生成器会直接破坏原生简洁的构建方式。

IoC 一般需要语言支持一些元编程才比较好用,go 就是个基本毫无元编程特性的语言,强上 IoC 我认为是徒增烦恼。
Saxton
2022-06-28 13:57:27 +08:00
@wangyzj 你说的这句话就已经脱离这个话题了,ioc 不是 java 的属性,他也不是任何一门语言的属性,他是一种思想,就跟 MVC 一样,难不成你在 go 里用 mvc 思想也是要把 go 变成跟 java 一样吗。
joesonw
2022-06-28 14:21:01 +08:00
反射的有 fx ,代码生成的有 wire 。
lysS
2022-06-28 14:56:52 +08:00
@Saxton 理论是这样的,但是实际上各个语言都有自己的味儿。不太喜欢串味
GeruzoniAnsasu
2022-06-28 15:24:50 +08:00
有啥好看的,拿锤看钉罢了

第一性原理: IOC 是什么,解决了什么问题

- 是什么: 当我在一个纯 OO 语言里,想用到某个 object 提供的方法时(比如 A 类的实例)需要 a=new A; a.method()
但我不希望当前写的这个逻辑依赖死 A 类,我希望有个「只要跟 A 类差不多的类实例」就行。于是可以使用接口+工厂,即 a=AFactory.New();a.method(),但这个实现依然要依赖特定的工厂,我希望写任何逻辑都能有一个万能工厂提供我要的接口,于是我不再在逻辑里写 a=new A 了,我写 a=THEGOD.provide("A"),或者在我的构造函数里写 CreateMe(I_WANT_AN_A a),这样我就有 a 了,怎么来的我不管,谁爱给谁给。

- 解决什么问题:
1. A 经常变化,我无法自己得到正确的 A ,但 GOD 可以,因为 A 会告诉 GOD 怎么生成自己
2. A 就算变了,我不需要配合改变,「代价」比较小




好,现在思考这两个问题在 golang 语境的意义

先说代价。因为这是最显著的差异
golang 是一个需要编译成二进制的静态类型语言,而且所有的代码都在同一个二进制里
它不像 java ,改了某一个模块,仅仅是那个模块的字节码发生变化。java 甚至可以动态加载字节码,也就说它完全可以 core 保持运行,临时下线一些功能,加载新的字节码,将原功能指到新加载的字节码上。
但 golang 不行。
****任意代码的修改都会导致整个程序重新编译****
编译时长之类的问题可以通过缓存文件优化,但是
****服务程序必须全部停止****
这一点是不会改变的。无论怎么折腾,golang 写的代码都必须重新编译,且**完全停止**原来的二进制程序运行再跑一个新的。
因此相比于 java 语境中「代价」有重大的运行时意义,golang 语境下「代价较小」的意义仅仅是保持代码工程的相对整洁罢了,但源码组织是整个软件工程中相当不重要的一环,我想没什么人会否认吧。大家都住在屎山,但没听说哪里的代码写成喜马拉雅能跑写成屎山就跑不了的。



再说问题 1

// service.go
var a IA = NewA()
a.method()

// interface.go
type IA interface{ method() }
func NewA() IA {
if 1{return a.NewA()}
if 2 {return a.v2.NewA()}
}

不行吗?
service 不引用 A 吧
interface 要改,但跟改 xml 本质上没什么区别吧



另外静态语言都不热衷这种框架,因为就算语言提供反射,它们也不像动态语言一样能「凭空造出一个类和实例」,从本质来说它们只能「改变指向类型的指针」,因此只要类型结构本身没有编译到二进制里,无论怎么折腾也造不出一个新类型。

这也就意味着 IOC 框架再怎么折腾也需要一个已经存在的类型实现,而非只要有存根就行。
因此在这些语言里,让框架为使用者寻找一个 IOC 容器的意义也仅仅只是在一个编译期就确定的类型映射表里找一个合适的类型罢了

那我代码里直接用这个静态映射不就好了,我干嘛还要「委托框架来帮我找」




----


拿你提的这个框架来说
1. 不使用这个框架,只用 interface 是不是也能从代码上解耦?
2. 使用这个框架,接口实现变化是不是一样的要「改代码+重新编译+重新部署」而且改动范围差不多?

golang 生态在微服务化跟 java 生态在 bean 化都是需求和语言特性 /限制的「磨合」,反向照猫画虎反正我的心态都是看个笑话
blless
2022-06-28 15:30:56 +08:00
IOC 是面向业务的,小项目估计无所谓,大项目业务复杂程度没有一些基础框架支持都自己实现挺麻烦的。不过开源的 wire 跟 dig 已经很好用了
EscYezi
2022-06-28 15:32:06 +08:00
比较好奇除了 ioc 还有什么其他好的依赖管理方案
fpure
2022-06-28 15:34:29 +08:00
现在一般用 spring ioc 的目的是为了 aop ,没有 aop 的 ioc 没有多大价值(解耦除外)
Yoock
2022-06-28 15:41:52 +08:00
不需要 IOC
EminemW
2022-06-28 16:14:24 +08:00
你们不用 IOC 的话,那些有状态的 service 都用全局变量存着么,比如 mysql, redis 之类的,虽然可以自己手动传进去,我用 ioc 就是省了到处 new ,不过我不会用阿里开源的东西,怕了
XCFOX
2022-06-28 16:48:09 +08:00
借楼提问:
按理来说后端开发里的 Service 类、Controller 类都是只被实例化一次,个人觉得这个复杂度根本不需要一个容器来管理依赖。个人觉得对象真正多的场景是游戏开发里,一个场景里经常包含成百上千的对象。
那么游戏开发领域会经常使用 IOC/DI 工具吗?
RubyJack
2022-06-28 16:55:18 +08:00
不需要的,只有搞 java 业务开发的人喜欢 ioc ,稍微底层一些的应用都不喜欢这玩意,可以看看 cpp 、rust 、golang 的大型开源项目,几乎见不到 ioc
GeruzoniAnsasu
2022-06-28 17:49:05 +08:00
@XCFOX

我写过一丁点 unity ,unity 本身就非常 DI 。对于场景设计器之类的东西静态定义的对象,框架控制着对象容器,写的逻辑会被框架反向绑定到对象上,逻辑类( XXBehavior : Behavior )是通过 unity 提供的 API 来获取自己绑定的物体实例的,物体不持有逻辑逻辑也不持有物体
zmal
2022-06-28 17:56:18 +08:00
“我理解是 Java 有 Spring 是因为它是纯面向对象的,没有函数这个概念只有方法,所以在一些需要函数的地方就需要通过 IoC 来注入一个单例。我作为使用者感觉到的是,IoC 是面向对象语言对于一些无状态的逻辑的妥协。”

个人这个认知不太准确,Java 的 IOC 框架 1 是为了解耦,2 是为了切面。单例对象是附赠功能。

不存在哪个语言应该是什么样子,语言最终会趋向于用户认为更好用的模样。
joesonw
2022-06-28 18:22:04 +08:00
全局变量的依赖和初始化顺序只能在外面注入的地方统一处理好,ioc 是每个服务的初始化和依赖都是自己声明自己的,我提供这个服务的依赖改变了其他人没必要知道。
cozof
2022-06-28 18:25:24 +08:00
@Abirdcfly grafana 使用的 ioc 是 wire 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/862639

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX