RPC 返回贫血模型情况下, 如何避免业务逻辑的分散?

2021-01-09 17:54:56 +08:00
 asanelder

如果是本地调用

interface UserService {
    User getUser(int userId);
}

返回的 user 可以有行为, 调用方不必取出 user 字段来进行逻辑判断.

但如果是 RPC 调用, 返回的 User 一般都没有行为. 调用方会取出数据字段来进行业务处理, 这样, 业务逻辑代码会分散到各个地方.

如果 RPC 调用返回的对象也是充血多好.

铁子们, 你们是如何处理 RPC 返回贫血模型呢? 如果返回贫血模型, 如何避免业务逻辑分散在各个地方?

2650 次点击
所在节点    程序员
18 条回复
xuanbg
2021-01-09 18:43:42 +08:00
你完全可以反序列化成充血模型
gjkv86
2021-01-09 18:51:43 +08:00
RPC 为何要返回充血模型?这种主要是传输对象的状态吧。 其结果需要有基于可以传输的 user 再有一到两层的包装再使用。你传输的只是对象的状态,这个可传输的对象确实没必要很复杂。 但上层使用时,需要有再次的封装,而不是直接拿来用。这样也避免了传输的模型发生了变化,把变化波及的上层。
wangyanrui
2021-01-09 19:06:11 +08:00
rpc 传输的是 dto,业务方使用时自行定义 bo 包裹一下呀🙄
chendy
2021-01-09 19:54:00 +08:00
把业务封装进模型到处传播,不还是把业务分散掉了么
daimazha
2021-01-09 19:54:23 +08:00
看一下六边形架构
YouLMAO
2021-01-10 00:46:36 +08:00
你们说的中文真的是脑壳疼了,微服务啊,user 服务当然是跟 user 相关的读写都在 user 微服务,怎么可能你取出 user rpc 的字段写自己逻辑呢,万一逻辑变了,你不就造成事故了吗,当然是 user 微服务做逻辑而不是上层做逻辑
yzbythesea
2021-01-10 06:05:10 +08:00
充血和贫血给我头都看晕了。
yzbythesea
2021-01-10 06:06:39 +08:00
你的意思是想执行 User.SayHi( ) 这种?这个正确做法是在 User Service 执行,然后提供 API,sayHiFromUser( )
taowen
2021-01-10 09:12:21 +08:00
user service 封装 user 可以做的一切事情,那啥事 user service 是不管的?
Kirsk
2021-01-10 10:23:22 +08:00
写一个公共项目 只放 service 接口 通过接口调用
Kirsk
2021-01-10 10:26:45 +08:00
@Kirsk 实现与调用分离 也就是长见的一个接口一个实现 不过如果实现写的垃圾比较容易出问题 至少保证每个业务实现的独立性
asanelder
2021-01-10 10:54:01 +08:00
@xuanbg #1 铁子意思是在 User 中添加相关业务方法? User 一般不都是生成的么?比如 thrift 使用 idl 定义, 然后生成 user 类。然后在生成的 User 类中再添加自定义方法?


@gjkv86 #2
@wangyanrui #3

也就是使用方有个 UserWrapper 之类的, 然后这个类有业务逻辑?

@daimazha #5 这个看过, 但不知道使用六边形架构怎么解决俺的问题, 铁子请明示

@YouLMAO #6 如果说微服务做业务逻辑,然后通过接口给 client 使用, 会出现这样一个问题。

可能 client 的业务要基于 user 的多个字段做操作, 比如 age 和 sex, 然后有四种结果, 然后把这个业务逻辑放到微服务中, 通过接口提供可能无法方便返回四种结果。


@yzbythesea #8 简单的业务逻辑可以放到微服务,但感觉有些复杂的, 通过一个接口不好满足。


@Kirsk #10 铁子的意思还是把业务放到接口后面?
yzbythesea
2021-01-10 11:21:01 +08:00
@asanelder 你举一个比较困惑的例子呢?有可能业务复杂是因为你们各服务过于耦合。
daimazha
2021-01-10 11:42:09 +08:00
@asanelder #12 很简单,六边形架构里面,你 rpc 查询的数据会有个 adapter 来转换成系统的领域对象
Kirsk
2021-01-10 19:10:25 +08:00
@asanelder 对的
ychost
2021-01-11 15:28:24 +08:00
提供二方包的时候打包一个 userValidator 公用等静态工具类就行了,直接返回充血模型不太友好,而且大多时候模型都是 idl 直接生成的,万一改漏了就麻烦了
asanelder
2021-01-11 21:57:33 +08:00
@daimazha #14 可以, 这个建议有启示感
@yzbythesea #13 嗯俺遇到真实的例子再补充
@ychost #16 就怕改漏
gjkv86
2021-01-11 22:44:03 +08:00
你叫 wrapper 也可以,或其他什么都行。但是从职责上,正如有朋友指出的,传输的确实是 dto 一类的东西。而你说的对象包括业务行为的这种类,应该是属于你自己建模的一部分,他应该不依赖于 user 数据是 rpc 来的还是 db 来的。我理解的不一定符合这理论那理论,但代码之所以这样那样的封装,很重要的一个目的就是为了适应变化,封装变化。最大限度的自己掌控适应变化。

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

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

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

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

© 2021 V2EX