1

我使用一个 Web 服务 API,它可以通过一个通用类型的Results 来提供某些基本信息,尤其是一个唯一的 ID。该唯一 ID 往往是——但不是必须——UUID由发送者定义,发送者并不总是同一个人(但 ID 在整个系统中是唯一的)。

从根本上说,API 的结果与此类似(用 Java 编写,但语言应该无关紧要),其中只有基本接口代表常见细节:

interface Result
{
    String getId();
}

class Result1 implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public OtherType1 getField1() { /* ... */ }
    public OtherType2 getField2() { /* ... */ }
}

class Result2 implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public OtherType3 getField3() { /* ... */ }
}

需要注意的是,每种Result类型可能代表一种完全不同的信息。其中一些不能与其他Results 相关,而其中一些可以,无论它们是否具有相同的类型(例如,Result1可能能够与 相关Result2,因此反之亦然,但有些ResultX可能存在无法相关,因为它表示不同的信息)。

我们目前正在实现一个系统,该系统接收其中一些Results 并在可能的情况下将它们关联起来,从而生成一个不同的Result对象,该对象是它关联在一起的内容的容器:

class ContainerResult implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public Collection<Result> getResults() { return containedResultsList; }
    public OtherType4 getField4() { /* ... */ }
}

class IdContainerResult implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public Collection<String> getIds() { return containedIdsList; }
    public OtherType4 getField4() { /* ... */ }
}

这是两个容器,它们呈现不同的用例。第一个,ContainerResult允许某人接收相关的详细信息以及实际完整的相关数据。第二个,IdContainerResult通过仅发送关联的 ID 来牺牲完整列表以支持带宽。进行关联的系统不一定与客户端相同,并且客户端可以接收Result这些 ID 将代表的 s,这旨在允许他们通过简单地接收 ID 在其系统上显示相关性。

现在,我的问题对某些人来说可能并不明显,而对其他人来说可能很明显:如果我只发送 ID 作为 的一部分IdContainerResult,那么如果客户Result没有单个 ID 存储?每个实现实际表示的数据类型Result在它们无法关联时会被隔离,这意味着在大多数情况下,如果不增加内存或存储负担,单个 ID 存储是不可能的。

我们提出的当前解决方案需要创建一种新类型的 ID,我们将其命名为TypedId,它将 XML 命名空间和 XML 名称与每个ResultResultID 结合起来。

我对该解决方案的主要问题是,它需要维护一个可变的类型集合,这些类型在发现时会更新,或者需要所有类型的先验知识,以便 ID 可以在任何客户端的系统上正确关联。不幸的是,我想不出更好的解决方案,但目前的解决方案感觉不对。

有没有人遇到过类似的情况,他们希望将 genericResult与其原始类型相关联,特别是考虑到 WSDL 的限制,并以更简洁的方式解决它?

4

1 回答 1

1

这是我的建议:

  1. 您希望“客户知道如何最终匹配结果”。因此,在您的响应中包含一个名为“RequestType”的额外鉴别器字段,一个字符串。

  2. 您希望避免“维护一个可变的类型集合,这些类型在发现时会更新,或者所有类型的先验知识,以便 ID 可以在任何客户端的系统上正确关联”。显然,每个客户端请求调用都知道 Result 将涉及到哪个处理区域。因此,您可以让客户端将“RequestType”字符串作为请求的一部分传递。只要 RequestType 是每个不同类型的客户端请求的唯一字符串,您的服务就可以处理和关联它,而无需硬编码任何知识。

  3. 这是请求和响应消息的 java 类的一个可能示例(即不是实际的服务端点):

    interface Request {
        String getId();
        String getRequestType();
        // anything else ...
    }
    
    interface Result {
        String getId();
        String getRequestType();
    }
    
    class Result1 implements Result {
        public String getId() { return uniqueValueForInstance; }
        public OtherType1 getField1() { /* ... */ }
        public OtherType2 getField2() { /* ... */ }
    }
    
    class Result2 implements Result {
        public String getId() { return uniqueValueForInstance; }
        public OtherType3 getField3() { /* ... */ }
    }
    
  4. 这是问题所在。上面的 (2) 和 (3) 没有给出完全动态的解决方案。您希望您的服务能够返回与每个不同请求相关的灵活记录结构。您有以下选择:

    4A) 在 XSD 中,将 Result 声明为单个强类型变体记录类型,并在 WSDL 中从单个服务端点和单个操作返回 Result。XSD 在声明变体记录结构时仍需要对鉴别器元素的值进行硬编码。

    4B) 在 XSD 中,为每个可能的客户端请求声明多个强类型唯一类型 Result1、Result2 等。在 WSDL 中,有多个唯一命名的操作来返回其中的每一个。这些操作可以跨一个或多个服务端点——甚至跨多个 WSDL。虽然这避免了将请求类型硬编码为特定字段本身,但它实际上并不是一个通用的独立于客户端的解决方案,因为您仍然通过为每个结果类型和每个操作创建唯一名称来显式硬编码以区分每个请求类型. 因此,任何明显的活力都是海市蜃楼。

    4C) 在 XSD 中,定义一个灵活的通用数据结构,该结构不是变体,但具有大量通用命名字段,能够处理所需的所有可能结果。示例字段可以是“stringField1”、“stringField2”、“integerField1”、“dateField1058”等。即使用极弱的类型并将负担放在客户端神奇地知道每个字段中的数据是什么。此选项可能非常通用,但通常被认为是糟糕的做法。它不优雅,非常难以阅读,容易出错,并且无论如何都内置了限制/假设 - 你怎么知道你有足够的通用字段包含在内?在您的情况下,(4A)可能是最好的选择。

    4D) 使用灵活的 XSD 模式设计策略 - 类型可替换性和使用“任何”元素。请参阅http://www.xfront.com/ExtensibleContentModels.html

    4E)针对您自己的工厂类方法使用@Produces @SomeQualifier 注释,该方法创建高级类型。这告诉 CDI 始终使用此方法来构造特定的 bean 类型和限定符。您的工厂方法可以有奇特的逻辑来决定在每次调用时构造哪个特定的低级类型。@SomeQualifier 可以有额外的参数来指导选择类型。这可能会将限定符的数量减少到只有一个。

    如果您使用 (4D),您将拥有一个灵活的服务端点设计,可以非常有效地处理不断变化的需求。但是您的服务实现仍然需要实现灵活的行为来决定为每个请求返回哪些结果字段。事实是,如果您对不同的数据结构有逻辑要求,您的代码必须知道如何为每个单独的请求处理这些数据结构,因此必须依靠某种形式的 RequestType / 唯一操作名称来区分。完全动态处理的任何目标(不适应每个客户对结果数据的需求)都是过于雄心勃勃的。

于 2013-03-11T00:59:53.147 回答