xsd:choice 并非总是最佳的 XML 模式构造。例如,包含 xsd:choice 的类型不能使用 JAX-RPC 代码生成器映射到用户友好的 Java? 类。在本文中,您将学习 xsd:choice 的一个功能等效项:多态性。
引言
xsd:choice 是常见的 XML 构造。不过,并不能总是方便地将 xsd:choice 映射到编程语言。例如,JAX-RPC 规范所定义的 Web 服务的 Java 映射并不提供从 xsd:choice 到 Java 的显式映射。只要 JAX-RPC 代码生成器在类型定义中遇到 xsd:choice,就会将该类型映射为 javax.xml.soap.SOAPElement。SOAPElement 属于 SAAJ API,不是一个非常用户友好的 API。
可以进行一些工作,以获得更好的 API。如果可以更改 XML 模式,则一个不错的选择就是使用多态性替代 xsd:choice。
xsd:choice 与多态性的对比
多态性表示具有“很多种形式”。例如,一个方法参数可以使用基类型进行声明。当调用此方法时,该参数的实例将为该类型的特定扩展。
对 xsd:choice 也可以进行类似的描述。可以使用描述所有可能 choice 的类型对方法参数进行声明。调用该方法时,该参数的实例将包含一个特定的 choice。
虽然实际的说法不同,但意思实质上却是一样的。
将简单 xsd:choice 类型映射到多态类型
为了将典型的 choice 类型转换为一个多态类型集,需要进行以下操作(假定 choice 类型 C 中包含的选择为 c1..cn):
构建一个抽象类 P,其中包含 C 的这些元素,但这些元素不是 choice 元素。
对于 c1..cn 中的每个 c,均为其构建一个扩展类型 E of P,该类型中包含 c 的元素。
通过示例理解概念总是更容易一些。让我们来看看 payment 选项的声明。清单 1 显示了一个 choice 类型。而清单 2 显示了转换为多态类型集的声明。
清单 1. choice 型 payment
清单 2. 多态型 payment
多态型 payment 示例比 choice 型 payment 示例更为冗长。这是因为 XML 不是真正的面向对象的编程语言,不能直接向其应用面向对象的功能。但这不应该对您有所影响。您很有可能会将 XML 映射到某种编程语言。作为使用该特定语言的开发人员,您不需要理会 XML 模式的样子,而只需要关心模式的语言映射的情况。
只有进行分析的时候,才应该了解 XML 模式的情况。例如,如果此模式是 Web 服务的一部分,而您希望比较这些类型的简单对象访问协议 (SOAP) 消息,从而确定消息大小本身是否影响性能。那么,让我们对这两个变体的实例进行比较。例如,假设我们对于金额为 10 美元的交易以支票付帐 (number 1050)。清单 3 显示了 choice 示例,而清单 4 显示了多态示例。(请注意,为了简化示例,我忽略了命名空间和前缀。)
清单 3. choice 型 payment 实例
清单 4. 多态型 payment 实例
正如您所看到的,清单 4 与清单 5 的唯一区别在于多态实例中包含类型信息。尽管这一差别值得注意,但通常并不重要。事实上,这可能会潜在地简化 SOAP 工程师的处理,因为 SOAP 工程师从一开始就知道此类型的情况,能够事先就选择恰当的反序列程序,而不用对实例进行分析和监视 choice 元素(在此例中为 check)的名称以确定类型。
因此使用多态方法并非比使用 choice 方法的开销大,而且可以提供更具用户友好性的语言映射。
对 maxOccurs 大于 1 的 xsd:choice 进行映射
大部分 choice 场景都与上面所示的例子相似。但 choice 可能具有大于 1 的 maxOccurs 属性。此映射过程相似,但需要进行额外的工作,以处理此新类型的新数组特性。
构建一个空的抽象类型 P。
使用 P 类型的元素替代 C 的 choice,且同时将 maxOccurs 属性从 choice 带到新元素中。
对于 c1..cn 中的每个 c,均为起构建一个 P 的扩展类型 E,该类型中包含 c 的元素。
例如,对清单 1 中的 Payment 类型进行修改,使其在 choice 上包含一个 maxOccurs=”unbounded” 属性。(请参阅清单 5,添加的部分用粗体突出显示。)
(此类型表示可以使用多个支付选项支付单笔款项:一部分用现金,一部分用支票,一部分用信用卡;或者任意组合。)
清单 5. 具有 maxOccurs 的 choice 型 payment
清单 6 显示了转换后的多态类型集。与清单 2 相比,所做的更改用粗体突出显示。
清单 6. 具有 maxOccurs 的多态 payment
请注意,PaymentOption 没有自身的字段。这或许有些奇怪,但这样并没有任何错误。它是抽象类型,因此永远不会存在 PaymentOption 实例,而只能存在其扩展。
请注意,还可以对典型的 choice 示例应用 maxOccurs 规则。但我希望您能够了解典型示例的简化规则的好处:少了一级需要进行处理的间接寻址。
多态性与 xsd:choice 的优势对比
与 xsd:choice 相比,多态性具有两个优势:扩展性和类型指示。
扩展性
就其本质而言,多态类型是可扩展的。抽象基类型可以具有任意数量的扩展,具体取决于是出于组织目的而将这些扩展分布到若干 .xsd 文件(一个组织可能仅接受现金和支票;而另一个组织可能仅接受信用卡和在线支付),还是随着时间推移会添加新扩展。
但 xsd:choice 本身是不可扩展的。如果希望以后不断添加 choice,或希望在不同 .xsd 文件中包含不同的 chioce 集,则要么在一个单态类型中定义所有可能的 choice,而让代码负责处理对于每种场景哪些可用,要么让很多类型包含相同的 choice 选项。这两种方法都不特别可靠。尽管可以扩展 choice 类型,并向扩展类型添加 choice,但为何不再向前迈一步,完全采用多态模式,而删除所有使用 xsd:choice 的地方呢?
类型指示
在这个 payment 示例中,其中一个 choice 就是 cash。不知您是否注意到这是一个采用相当奇怪的方式定义的 choice?对于现金,除了必须知道数量之外,还需要知道别的什么?什么都不用知道了。而这正是添加 nillable=”true” 属性的原因;可以对 cash 元素进行赋值,但这没有意义。现金支付的实例可能与清单 7 所示类似。
清单 7. choice 型现金支付实例
此处实际上是想指出这是现金支付。但在 choice 中,如果没有占位符就不能指示这一点。
在清单 2 中的 CashPayment 类型中,我一并提供了 cash 元素,因为我直接应用了转换规则,但并非真的需要这个元素。实际上,所需的就是指示此为一个 cash 类型,没有别的了,而多态性的特性就能够做到这一点。因此,CashPayment 选项将扩展 Payment 类型,但却不会添加自身的新内容。清单 8 显示了此类型的一个实例。
清单 8. 改进后的多态 CashPayment
清单 9. 多态现金支付示例
总结
在某些场景中,xsd:choice 并非可使用的最佳类型。例如,当使用 JAX-RPC 映射规则将 choice 类型映射到 Java 语言时,最终得到一个 Java 映射,但用户友好性并不好。如果可以控制模式,则可能希望将包含 xsd:choice 的类型转换为一个多态类型集。这将不仅能得到一个更为用户友好的映射,而且多态性比 xsd:choice 更可靠。
关于作者
Russell Butek 是一位 IBM Web 服务顾问,曾是 IBM WebSphere Web 服务引擎的开发人员之一。他也是 JAX-RPC Java Specification Request (JSR) 专家组成员之一。他曾参与了 Apache 的 AXIS SOAP 引擎的实现(使 AXIS 1.0 符合 JAX-RPC 1.0 规范)。之前,他曾做过过 IBM CORBA ORB 的开发,且曾是很多 OMG 任务组的 IBM 代表,曾负责可移植式拦截器任务组的工作。可通过 butek@us.ibm.com 与 Russell 联系。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
内存数据网格提供商一头扎进Java
10年的时间里,应用性能解决方案提供商Alachisoft一直在用NCache(针对N-Tier和网格计算.NET应用的内存计算和数据网格产品)为.NET社区服务。
-
遇到这样一个问题:通过java service wrapper部署应用,wrapper进程占用的内存会一直升高, 直到把内存吃完应用崩溃,但是这个wrapper
遇到这样一个问题:通过java service wrapper部署应用,wrapper进程占用的内存会一直升高 […]
-
Google App Engine for Java 对于目前中国需要学习吗?
-
前无古人后无来者的Java平台
开发人员一直在致力于保持Java的活力,经过20年后,我们感觉从来没有更好的、更令人激动的时刻如同Java社区一样。