反序列化嵌套/分层数据,无强类层次结构

ws51t4hk  于 2021-08-25  发布在  Java
关注(0)|答案(1)|浏览(254)

我有一个设计/架构问题。我目前正在尝试将数据优雅地解析到单个数据类中。但数据是通过各种协议 Package 的: A(B(C)) . 其主要思想是能够在不同的层(如 A(D(E))B(C) ). 但最后我只想返回一个包含所有内容的对象。
我目前的方法是使用继承来抽象每个类的层/协议。但是使用这种方法,我不能灵活地在不需要重新编码类的情况下切换层。请参见下面的简化示例和示例数据。
因此,我的问题是:是否有一种模式可以在保持灵活性的同时正确实现分层数据的反序列化?

{                                               // Layer A
  "timestamp": "2021-07-06T10:01:00.000Z",
  "value": {                                    // Layer B
      "timestamp": "2021-07-06T10:00:30.000Z",
      "src": "any",
      "data": "some complex data string"        // Layer C
  }
}
class _Base { public JsonNode parse(JsonNode data) { return data; } }
class A extends _Base {
  public Instant aTimestamp;
  public JsonNode parse(JsonNode data) {
    JsonNode remaining = super.parse(data);
    aTimestamp = Instant.parse(remaining.get("timestamp").asText());
    return remaining.get("value");
  }
}
class B extends A {
  public Instant bTimestamp;
  public String src;
  public JsonNode parse(JsonNode data) {
    JsonNode remaining = super.parse(data);
    bTimestamp = Instant.parse(remaining.get("timestamp").asText());
    src = remaining.get("src").asText();
    return remaining.get("data");
  }
}
class C extends B {
  public String[] data;
  public JsonNode parse(JsonNode data) {
    JsonNode remaining = super.parse(data);
    this.data = remaining.asText().split(" ").
    return null;
  }
}
shstlldc

shstlldc1#

如果我在c#中这样做,我会尝试使用接口——因此,如果你想用b替换d,那么只要类实现了可能工作的接口。继承很好,但不如接口灵活。继承是一种东西,接口有一种东西。参见:面向对象语言中的has-a、is-a术语
e、 g.(伪代码):

interface ILevel1{
  Instant bTimestamp;
  String src;
  ILevel2 iLevel2;
}

interface ILevel2{
  String[] data;
}

// your new pseudo code:

class B : ILevel1 {
  public Instant bTimestamp;
  public String src;
  public ILevel2 parse(JsonNode data) {
    JsonNode remaining = super.parse(data);
    bTimestamp = Instant.parse(remaining.get("timestamp").asText());
    src = remaining.get("src").asText();
    return remaining.get("data");
  }
}

class C : ILevel2 {
  public String[] data;
  public JsonNode parse(JsonNode data) {
    JsonNode remaining = super.parse(data);
    this.data = remaining.asText().split(" ").
    return null;
  }
}

class D : ILevel1 {
  public Instant bTimestamp;
  public String src;
  public ILevel2 parse(JsonNode data) {
    JsonNode remaining = super.parse(data);
    bTimestamp = Instant.parse(remaining.get("timestamp").asText());
    src = "SRC is totally overrated";
    return remaining.get("data");
  }
}

这有意义吗?我的伪代码可能不正确,但关键是类b(和d——实现ilevel1的任何东西)将返回实现ilevel2的东西。
通常我在c#中工作,虽然我已经完成了json反序列化,但我不是Maven。
回应评论更新
我想我在伪代码中犯了一个错误——已经更正了。
在您的示例中,super.parse(数据)是什么,因为接口没有提供实现?
更正接口不正确,但类不正确。。。因此,虽然接口充当占位符,但在运行时将加载实际的实现,因此它仍然可以执行一些实际的解析。有道理?
最终如何将这些实现组合成一个类/对象?
您需要一些逻辑,这些逻辑基于一些输入,知道要示例化给定接口的哪个实现。有很多方法可以解决这个问题:一个可能位于某个公共库中的工厂,或者在类中编写代码。
我们的假设是,控制运行时加载哪个实现的规则可以编码到您的解决方案中的某个位置,例如嵌入到实现本身中,或者由位于实现外部的公共库驱动的数据。
下面是每种方法的一个伪示例:

// Decide in the factory:
public ILevel1 Level1Factory(string someinput)
{
  if(droid=='K2SO')
    return new B()
  else
    return new C()
}

// Decide in-line in the class - but still abstract out the factory:
class X : ILevel1 {
  public Instant bTimestamp;
  public String src;
  public ILevel2 myLevel2;

  JsonNode parsedData = super.parse(data);
  if(droid=='K2SO')
    myLevel2 = Factory.MakeL2Type001(parsedData);
  else
    myLevel2 = Factory.MakeL2Type002(parsedData);

  ...
}

相关问题