不限语言,谈谈如何避免循环依赖?

2022-09-05 16:08:10 +08:00
 vczyh

如何避免循环依赖,这个其实和语言没什么关系。

解决方式也比较简单,但是随着业务复杂起来,比较容易出现这种情况。

就用 Java 来说,大家怎么避免 service 互相调用的。

6988 次点击
所在节点    Java
65 条回复
frank1256
2022-09-05 17:02:52 +08:00
@vczyh 不是额,检查出来就提示哪里出现循环了,改掉那一处就行了,设计之初就想好的话,太考验设计了。代码里噼里啪啦的 service 疯狂创建,来不及设计了
vczyh
2022-09-05 17:02:54 +08:00
@Jooooooooo spring 是一定程度上是支持的,但是 Golang 是禁止的。
vczyh
2022-09-05 17:03:16 +08:00
@VeryZero 那这一层一般叫什么呢?
vczyh
2022-09-05 17:03:50 +08:00
@Kontinue 是的,主要是后面会出现的,前期没有这个问题。
vczyh
2022-09-05 17:04:31 +08:00
@frank1256 事实确实是你说的那样,很蛋疼。
libook
2022-09-05 17:05:09 +08:00
同级尽量避免互相调用,看是否重新规划服务层级和为服务划分是否能解决问题。
vczyh
2022-09-05 17:05:51 +08:00
有没有同学有比较好的实践
vczyh
2022-09-05 17:07:00 +08:00
@libook 我也是这么认为
fiypig
2022-09-05 17:07:15 +08:00
= = Java 真的会出现这情况,那时候在学就是这样,反倒 go 就不会出现这情况,没那么乱。。。
ChoateYao
2022-09-05 17:07:37 +08:00
Module 之间加多一个 转换层把其他 Service 的接口当成远程接口,模块内也不存在 Service 互相调用的情况,如果出现那么一定是业务逻辑抽离不干净。
Jooooooooo
2022-09-05 17:09:14 +08:00
@vczyh 你说的是系统层面的循环调用, 我说的是业务层面的循环调用.

如果你真想解决问题, 得解决后面这个问题. 前面这个问题更是一个小问题.
vczyh
2022-09-05 17:12:32 +08:00
@ChoateYao 那意思是
之前:UserService.get(long id):获取用户信息->根据用户 ID 获取所有订单信息(造成 UserService 依赖 OrderService )
改成:为了禁止 service 之间调用,在 service 层上加一层,在这一层组合 UserService 和 OrderService
可以这么理解吗?
ChoateYao
2022-09-05 17:17:05 +08:00
@vczyh 你的场景是 OrderService 依赖 UserService ,你的主要场景是订单,不是用户。

加多一层 ACL (防腐层)

UserInfoAdpater 主要实现调用 UserService 的 get 方法放在 OrderModule 的 ACL 里面,转换成你想要的 User 对象

在 OrderService 里面调用 UserInfoAdpater 得到 User 对象之后再查询 User Order Items
frank1256
2022-09-05 17:23:29 +08:00
@ChoateYao 看到 DDD 头疼
nothingistrue
2022-09-05 17:31:18 +08:00
@vczyh #32 如果 User 依赖 Order ,并且 Order 又反过来依赖 User ,那说明你们并没有把 User 跟 Order 解开。上面再套一层,还是没有解开,治标不治本。而且还是用毒药治那种,因为层是个很重的东西,加一层的成本是很高的。

相互依赖,一个原因是同层之间不同模块没解开造成的。对于你这个例子,根据用户 ID 获取所有订单信息,这实际上只是 Order 自身的事,跟 User 屁关系都没有。请注意用户 ID 作为不变的值,即使它是通过 User 生成的,它也不属于 User 而是属于全局,或者所有对它感兴趣的模块。

另一个原因,是根本没用好层造成的。分层既然隔离了技术,那自然要把基于技术的模块划分也给隔离了,不同层的模块划分原则是不一样的。还拿你这个例子来说,根据用户 ID 获取所有订单信息,在 UI 层往往是属于“我的……”这种用户个人资料模块的,但在业务逻辑层,或者数据模型层,它是属于 Order 模型的。
zhuangzhuang1988
2022-09-05 17:39:32 +08:00
直接用 F#
编译都依赖文件顺序
vczyh
2022-09-05 17:54:19 +08:00
@nothingistrue
情况 1:查询用户,带出对应的订单(造成 User 依赖 Order.getListByUserId(long userId)接口)
情况 2:查询订单,带出用户的某些信息(造成 Order 依赖 User.getSomeInfo(long userId))
请问这种 service 互相依赖怎么解决?
urnoob
2022-09-05 18:01:42 +08:00
A 和 B 中有循环依赖,把循环依赖的部分放到 A 或者 B ,或者放进新创建的 C
xuanbg
2022-09-05 18:33:14 +08:00
@nothingistrue 是的,代码没写对地方,加多少层都没卵用。作为一个程序员,把代码写对地方才是第一重要的事。
lmshl
2022-09-05 18:34:07 +08:00
笨方法:延迟初始化
普通方法:抽出一层
聪明方法:不要用类来组织它们,自然就不存在循环依赖了

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

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

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

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

© 2021 V2EX