V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
asanelder
V2EX  ›  程序员

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

  •  
  •   asanelder · 2021-01-09 17:54:56 +08:00 · 2626 次点击
    这是一个创建于 1416 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果是本地调用

    interface UserService {
        User getUser(int userId);
    }
    

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

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

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

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

    18 条回复    2021-01-11 22:44:03 +08:00
    xuanbg
        1
    xuanbg  
       2021-01-09 18:43:42 +08:00
    你完全可以反序列化成充血模型
    gjkv86
        2
    gjkv86  
       2021-01-09 18:51:43 +08:00
    RPC 为何要返回充血模型?这种主要是传输对象的状态吧。 其结果需要有基于可以传输的 user 再有一到两层的包装再使用。你传输的只是对象的状态,这个可传输的对象确实没必要很复杂。 但上层使用时,需要有再次的封装,而不是直接拿来用。这样也避免了传输的模型发生了变化,把变化波及的上层。
    wangyanrui
        3
    wangyanrui  
       2021-01-09 19:06:11 +08:00 via Android
    rpc 传输的是 dto,业务方使用时自行定义 bo 包裹一下呀🙄
    chendy
        4
    chendy  
       2021-01-09 19:54:00 +08:00
    把业务封装进模型到处传播,不还是把业务分散掉了么
    daimazha
        5
    daimazha  
       2021-01-09 19:54:23 +08:00
    看一下六边形架构
    YouLMAO
        6
    YouLMAO  
       2021-01-10 00:46:36 +08:00 via Android
    你们说的中文真的是脑壳疼了,微服务啊,user 服务当然是跟 user 相关的读写都在 user 微服务,怎么可能你取出 user rpc 的字段写自己逻辑呢,万一逻辑变了,你不就造成事故了吗,当然是 user 微服务做逻辑而不是上层做逻辑
    yzbythesea
        7
    yzbythesea  
       2021-01-10 06:05:10 +08:00
    充血和贫血给我头都看晕了。
    yzbythesea
        8
    yzbythesea  
       2021-01-10 06:06:39 +08:00
    你的意思是想执行 User.SayHi( ) 这种?这个正确做法是在 User Service 执行,然后提供 API,sayHiFromUser( )
    taowen
        9
    taowen  
       2021-01-10 09:12:21 +08:00 via Android
    user service 封装 user 可以做的一切事情,那啥事 user service 是不管的?
    Kirsk
        10
    Kirsk  
       2021-01-10 10:23:22 +08:00 via Android
    写一个公共项目 只放 service 接口 通过接口调用
    Kirsk
        11
    Kirsk  
       2021-01-10 10:26:45 +08:00 via Android
    @Kirsk 实现与调用分离 也就是长见的一个接口一个实现 不过如果实现写的垃圾比较容易出问题 至少保证每个业务实现的独立性
    asanelder
        12
    asanelder  
    OP
       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
        13
    yzbythesea  
       2021-01-10 11:21:01 +08:00
    @asanelder 你举一个比较困惑的例子呢?有可能业务复杂是因为你们各服务过于耦合。
    daimazha
        14
    daimazha  
       2021-01-10 11:42:09 +08:00
    @asanelder #12 很简单,六边形架构里面,你 rpc 查询的数据会有个 adapter 来转换成系统的领域对象
    Kirsk
        15
    Kirsk  
       2021-01-10 19:10:25 +08:00 via Android
    @asanelder 对的
    ychost
        16
    ychost  
       2021-01-11 15:28:24 +08:00
    提供二方包的时候打包一个 userValidator 公用等静态工具类就行了,直接返回充血模型不太友好,而且大多时候模型都是 idl 直接生成的,万一改漏了就麻烦了
    asanelder
        17
    asanelder  
    OP
       2021-01-11 21:57:33 +08:00
    @daimazha #14 可以, 这个建议有启示感
    @yzbythesea #13 嗯俺遇到真实的例子再补充
    @ychost #16 就怕改漏
    gjkv86
        18
    gjkv86  
       2021-01-11 22:44:03 +08:00 via iPhone
    你叫 wrapper 也可以,或其他什么都行。但是从职责上,正如有朋友指出的,传输的确实是 dto 一类的东西。而你说的对象包括业务行为的这种类,应该是属于你自己建模的一部分,他应该不依赖于 user 数据是 rpc 来的还是 db 来的。我理解的不一定符合这理论那理论,但代码之所以这样那样的封装,很重要的一个目的就是为了适应变化,封装变化。最大限度的自己掌控适应变化。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1038 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 20:38 · PVG 04:38 · LAX 12:38 · JFK 15:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.