json 里面有互斥的字段,要怎么序列化成对象?
比如下面的例子里,要么只有refund
字段,要么只有purchase
,而且两个字段里的结构是不一样的。
{ "id": "1234567890", "amount": 100, "refund" { "date": "2021-04-23T18:25:43.511Z", "confirmed": true, "refund_id": 1234456 } } { "id": "1234567890", "amount": 100, "purchase": { "date": "2021-04-23T18:25:43.511Z", "purchase_id": 789621 } }
现在到的最粗暴的办法,是把每个字段都塞进对象。但这太难看了,而且容易造成混乱。
这种结构下,要怎么设计对象的结构比较好?
1 2kCS5c0b0ITXE5k2 2021-09-01 14:17:57 +08:00 应该要好好想想 为什么 id 能有重复的吧. |
2 xiaokongwu 2021-09-01 14:19:27 +08:00 @emeab 人家只是随便写个例子吧 |
![]() | 3 binux 2021-09-01 14:20:56 +08:00 via Android 两个类,反序列化之前判断一下是哪个。 |
![]() | 4 fkmc 2021-09-01 14:21:49 +08:00 加 type 结构保持一致 |
5 xiaokongwu 2021-09-01 14:23:34 +08:00 要不用 map 接吧…… |
![]() | 6 jenlors 2021-09-01 14:24:10 +08:00 结构合并在一起,某些值可为空 |
7 micean 2021-09-01 14:26:21 +08:00 自己写个自定义的反序列化适配就可以了,但是还不如塞 2 个对象呢 |
![]() | 8 YJi 2021-09-01 14:31:38 +08:00 要是非用一个类,感觉只能枚举所有字段了.. (蹲一个其他方案 |
9 thtznet 2021-09-01 14:35:32 +08:00 动态 |
![]() | 10 BigDogWang 2021-09-01 14:36:13 +08:00 接口设计的不合理吧,难不成你要用的时候还要判断下这两个对象哪个不为 null ? |
![]() | 11 lower 2021-09-01 14:39:43 +08:00 type: 区分类型 data:存数据,直接用 Object 或者泛型 |
![]() | 12 cpstar 2021-09-01 14:40:02 +08:00 json 本来就不是固定结构的,用编程语言的话叫不是强类型 反序列化到对象,肯定得是两个类了,一个类是 refund,一个类是 purchase,至于这两个类是否从一个 super class 中派生,那是另外一个事情了。 然后上工厂模式,factory.unserialize(json) |
![]() | 13 Puteulanus 2021-09-01 14:40:10 +08:00 早点判断早点分开比较好吧,感觉是过度抽象了,两个东西内容不一样硬要捏在一起的话,后面写会到处是 if 判断的 |
![]() | 14 sankemao 2021-09-01 14:44:43 +08:00 加一个 type 用以区分 |
![]() | 15 chendy 2021-09-01 14:46:27 +08:00 既然传进来之后要做区分,为什么不直接在接口一层就做区分呢? 不过确实存在一些一个接口怼所有类型的情况(比如一些 webhook ),我的做法是做一个包含所有可能字段的大类接参数进来(还好没有冲突)然后区分类型转换成需要的类型然后传给对应的业务 |
![]() | 16 qinxi 2021-09-01 14:46:28 +08:00 加个 type 区分一下 然后用多态 JsonSubTypes |
![]() | 17 Kilerd 2021-09-01 15:20:48 +08:00 via iPhone rust 里面的 enum 可以很好的处理这种情况。其他语言就只能自己些 deserializer 去判断 type 了 |
![]() | 18 x97bgt OP |
19 zhady009 2021-09-01 16:11:44 +08:00 感觉类设计有点不太合理 建议还是根据 refund 字段是否为空来分组分开来分别序列化成对应的类型 |
20 Jooooooooo 2021-09-01 16:16:09 +08:00 弄个 type 呀. |
![]() | 21 bnm965321 2021-09-01 16:17:15 +08:00 union type. 在 TS 里面也能很简单的处理 |
![]() | 23 ysc3839 2021-09-01 17:07:09 +08:00 如果是 C++ 的话,我会选择定义两个 struct,然后用 std::variant 。 |
24 goHomeAdmin 2021-09-01 17:07:12 +08:00 data { type_1: {}, type_2: {}, } protobuf 中的 one of 使用 |
![]() | 25 ysc3839 2021-09-01 17:11:22 +08:00 Java 的话,我会选择把两个字段都写进去,允许 null 。 |
![]() | 26 Duolingo 2021-09-01 17:23:56 +08:00 这不是用一个类就能解决的么 |
![]() | 27 passerbytiny 2021-09-01 17:32:46 +08:00 via Android 你这个不管对应到类还是对应到关系数据,都是两种数据类型,这就不要再想反序列化成一个类了。 |
![]() | 28 passerbytiny 2021-09-01 17:36:14 +08:00 via Android 这种结构不稳定的数据格式,是符合 JSON 规范和接口数据规范的,但不符合面向对象数据格式,建议不要做反序列化,直接当成 JSON 读取,用 jsonpath 的形式 |
![]() | 29 jiorix 2021-09-01 17:57:17 +08:00 类设计可以更抽象点,建议把差异的字段抽象为值。 |
![]() | 30 james2013 2021-09-01 20:14:18 +08:00 { "id": "1234567890", "amount": 100, "refund": { "date": "2021-04-23T18:25:43.511Z", "confirmed": true, "refund_id": 1234456 } "purchase": { "date": "2021-04-23T18:25:43.511Z", "purchase_id": 789621 } } { "id": "1234567890", "amount": 100, "purchase": { "date": "2021-04-23T18:25:43.511Z", "purchase_id": 789621 } } |
![]() | 31 james2013 2021-09-01 20:15:43 +08:00 类中放 refund 和 purchase2 个子类就可以了 |
![]() | 32 lululau 2021-09-01 22:39:29 +08:00 class RootEnt { String id; int amount; RefundEnt refund; PurchaseEnt pruchase; } |
![]() | 33 mingl0280 2021-09-02 04:07:46 +08:00 via Android class Json { string id; int amount; Purchase purchase; Refund refund; }; |
![]() | 34 rububio 2021-09-02 13:15:06 +08:00 via Android 当然是用 Discriminate Union 啊。 |