使用 UML 设计 XML 模式

发表于:2007-05-25来源:作者:点击数: 标签:业务设计umlxml模式
将业务概念转换成 XML 词汇表 补充框架 用构造型扩展 UML 从 UML 模型生成 XML 模式 结束语 参考资料 关于作者 统一建模语言(Unified Modeling Language, UML)是一种业界标准,当以 面向对象 的方法构建软件系统时,用它来对业务概念建模。就信息和命令的
将业务概念转换成 XML 词汇表
补充框架
用构造型扩展 UML
从 UML 模型生成 XML 模式
结束语
参考资料
关于作者
统一建模语言(Unified Modeling Language, UML)是一种业界标准,当以面向对象的方法构建软件系统时,用它来对业务概念建模。就信息和命令的传输方面而言,近来 XML 已经愈发成为实现这些系统的关键因素。XML 模式用于定义和限制被交换 XML 的本质,因此它成为了人们注意的焦点。本文讨论了 UML 在设计 XML 模式方面的用法,并为使用 UML 框架创建 XML 词汇表提供了一种实用的方法。

在将 UML 框架用于构造 XML 模式时,必须考虑三个问题:

  • UML 和 XML 模式之间的互补性
  • 如何扩展 UML 以捕获模式提供的全部功能
  • 根据 UML 图设计 XML 模式的能力

为了有助于在本文中讨论这两种框架,我将使用一家虚拟公司:BALTIC Shipping 作为示例。

BALTIC Shipping 是一家国际性的运输公司,专门从事美国到东欧的货运业务。该公司希望创建一种机制,用于跟踪从其纽约总部到各分公司(如位于爱沙尼亚塔林(Tallinn)的一个分公司)的装运物情况(请参阅图 1)。当产品起运时,总部通过电子方式以 XML 形式发送关于本次装运物的信息。一旦货物抵达目的地,分公司将以电子方式把确认信息发回给总部。

所有订单和确认数据都以 XML 文档形式交换,必须设计模式来概括文档的结构。用于对装运订单建模的业务构造也用来与库存跟踪系统(Inventory Tracking System)交换信息,库存跟踪系统随时都知道公司现有哪些包装箱要交运。本文讨论了构造 XML 模式时使用 UML 的功效,这些 XML 模式定义了这些以 XML 格式进行数据传输的业务构造。

图 1. BALTIC Shipping 工作流

补充框架

UML 及其面向对象的建模可以为构建 XML 模式提供补充。您可以方便地用 UML 中的图形符号来表示业务概念,并开始设计您的 XML 模式。

建模的价值
有关 UML 在创建 XML 模式时的优点的讨论假定了面向对象建模的价值是已知的。在我上一篇文章“Create flexible and extensible XML schemas”中,我讨论了使用面向对象方法构建 XML 模式的重要性和价值。使用 UML 设计面向对象系统除了具有技术优势之外,UML 还提供了一个公共媒介,业务团队和技术团队可以通过该媒介方便地交流看法。业务分析人员是软件系统(尤其是一个包含特定于领域信息的系统)中的关键协作者。由于业务分析人员参与设计 XML 文档的过程,因此软件架构设计师和业务分析人员之间默契的合作对于项目的成功变得非常重要。UML 的图形符号使得技术人员和非技术人员很容易就诸如 Shipping Order 的定义之类的业务概念达成一致,因此也就加速并促进了项目的完成。

互补
设想一下,BALTIC Shipping 的业务经理找到您,请您对一个 XML 模式建模,该模式将对在公司内不同系统之间传输的信息进行形式化。他与您坐下来,一起讨论该领域的业务概念。您可以在纸上绘制一些草图,但 UML 使用图和符号对这些概念建模提供了一种更好的正式方法。

图 2. UML 图

图 2 中的 UML 图里勾画出了 Shipping Order 的业务定义。BALTIC Shipping 将 Shipping Order 定义为包含 ShippingIdOriginDestinationOrder。无论何时交换有关 Shipping Order 的任何数据,它都考虑这些必需的信息。此外,UML 图也用来表示组成 Origin 或 Order 的内容。所显示的 Origin 和 Destination 的类型与类型 Address 相同,BALTIC Shipping 将具有下列特征的 Address:Name、Street、City 和 Country 存储在其数据库中。这些都是业务概念,数据库模型、软件程序以及供经理和业务伙伴们阅读的文档中都用到了它们。这些概念还包括基数(Order 可以包含许多 Item)、继承(Origin 继承 Address 的全部特征)以及依赖关系(Order 依赖于其 Item 的详细信息);UML 图捕获了所有这些关系。由于您希望您的 XML 文档携带 Shipping Order 信息,因此下一步就是设计符合草拟的 UML 图的 XML 模式。下面的模式表示 UML 图(参阅图 2)到 XML 模式的映射。

清单 1. ShippingOrder.xsd
clearcase/" target="_blank" >cccccc" border="1">

            <?xml version="1.0" encoding="UTF-8"?>
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">
            <xs:include schemaLocation="DataTypes.xsd"/>
            <xs:element name="shippingOrder">
            <xs:complexType>
            <xs:sequence>
            <xs:element name="shippingId"type="int"/>
            <xs:element name="origin" type="Origin"/>
            <xs:element name="destination" type="Destination"/>
            <xs:element name="order" type="Order"/>
            </xs:sequence>
            </xs:complexType>
            </xs:element>
            </xs:schema>
            

正如您在清单 1 中可看到的那样,UML 中的 Shipping Order 类由模式中的复杂类型 shippingOrder 表示。正如业务推荐的那样,Shipping Order 由 shippingIdOriginDestinationOrder 组成。要说明的一点是,我将 Origin 类型连同其它一些通用类型一起放在了 DataTypes 模式中(请参阅清单 2)。DataTypes 库便于存储诸如 Address 定义之类的可重用类型,整个公司不同项目的 XML 文档中都使用了这些可重用类型。

在 UML 图中(请参阅图 2),Address 是一种抽象类型,单词“Address”用斜体书写以表示它是抽象类型。类型 OriginDestinationAddress 继承了特征 Name、Street、City 和 Country。为可重用类型创建蓝图被认为是一种好的面向对象设计。在 XML 模式中(请参阅清单 2),我已经通过使用关键字 abstract="true" 将类型 Address 指定为抽象类型。类型 OriginDestination 模仿了我最初在 UML 图中所勾画的设计,这里我使用 extension base="Address" 来表明它们继承了 Address 的特征。此外,我还捕获了这样一个业务模型:通过用代码 type="Item" maxOccurs="unbounded"Order 可以包含许多 Item

清单 2. DataTypes.xsd

            <?xml version="1.0" encoding="UTF-8"?>
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">
            <xs:complexType name="Address" abstract="true">
            <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="street" type="xs:string"/>
            <xs:element name="city" type="xs:string"/>
            <xs:element name="country" type="xs:string"/>
            </xs:sequence>
            </xs:complexType>
            <xs:complexType name="Origin">
            <xs:complexContent>
            <xs:extension base="Address"/>
            </xs:complexContent>
            </xs:complexType>
            <xs:complexType name="Destination">
            <xs:complexContent>
            <xs:extension base="Address"/>
            </xs:complexContent>
            </xs:complexType>
            <xs:complexType name="Order">
            <xs:sequence>
            <xs:element name="item" type="Item" maxOccurs="unbounded"/>
            </xs:sequence>
            </xs:complexType>
            <xs:complexType name="Item">
            <xs:sequence>
            <xs:element name="description" type="xs:string"/>
            <xs:element name="weight" type="xs:double"/>
            <xs:element name="tax" type="xs:double"/>
            </xs:sequence>
            </xs:complexType>
            </xs:schema>
            

如果您是从头开始设计 XML 模式的,那么将很难只使用 XML 写下对象类型。此外,要想向不熟悉 XML 模式术语的业务经理解释它们也几乎是不可能的。根据 UML 图,您可以有效地转换公司的业务概念,然后使用您面前的这一可视化表示创建 XML 模式。以下是运用您创建的模式为一批从纽约运往塔林的草莓酱生成的实例文档。

清单 3. ShippingOrder.xml

            <?xml version="1.0" encoding="UTF-8"?>
            <shippingOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="C:\\schemas\\ShippingOrder.xsd">
            <shippingId>09887</shippingId>
            <origin>
            <name>Ayesha Malik</name>
            <street>100 Wall Street</street>
            <city>New York</city>
            <country>USA</country>
            </origin>
            <destination>
            <name>Mai Madar</name>
            <street>Liivalaia 33</street>
            <city>Tallinn</city>
            <country>Estonia</country>
            </destination>
            <order>
            <item>
            <description>Ten Strawberry Jam bottles</description>
            <weight>3.141</weight>
            <tax>7.60</tax>
            </item>
            </order>
            </shippingOrder>
            

基础知识
虽然在这个示例中很容易看出使用 UML 的好处,但 BALTIC Shipping 示例确实是 UML 和 XML 模式之间的互补性的典型表现吗?我已经指出:XML 模式可以捕获 UML 图中所表示的信息。但是,现在让我们反过来分析,问一问 UML 图是否能够捕获 XML 模式提供的所有功能。XML 模式极大地丰富了对 XML 文档的形式化,而且初步分析表明 XML 模式的大多数基本功能都可以由 UML 图表示。请考虑 XML 模式的一些重要原则:

1. 类型
XML 模式既有内置数据类型(如 intdouble),也有通过构造得到的类型(如表示 Address 组件的复杂类型)。类型的生成是面向对象设计的一个重要方面,也是模块化、灵活性和封装性所必需的。UML 中,提供了内置的数据类型,而新类型则可以使用类的结构来构建。

XML 模式还具有用户定义的类型,用 W3C 的话说,这种类型“允许创建用户定义的数据类型,如派生自现有数据类型的数据类型,并且它可以对它的某些特性(例如,范围、精度、长度以及格式)加以限制。”对于特殊的或用户定义的类型,UML 允许对其基本概要文件加以扩展,这类扩展被称为构造型用构造型扩展 UML 这一部分对构造型进行了详细讨论。

2. 属性
XML 模式中的属性对两件事情有用:

  • 捕获关联。例如,Order 可以包含许多 Item。在 XML 模式中这被写为 maxOccurs="unbounded"。在 UML 中,关联与模型中的两个或多个类有关,关联由带数字的单箭头表示,数字意味着该关联的多重性。
  • 显示可能内在地链接到某个元素的附加信息。XML 模式中有这样一个元素和属性配对的示例:带有 currency 属性的 tax 元素。清单 4 中显示了向元素 tax 添加属性的示例。
清单 4. 添加属性

            <xs:element name="tax">
            <xs:complexType>
            <xs:simpleContent>
            <xs:extension base="xs:double">
            <xs:attribute name="currency" type="xs:string" use="required"/>
            </xs:extension>
            </xs:simpleContent>
            </xs:complexType>
            </xs:element>
            

可以在 UML 图中捕获属性来作为类的属性。然而,必须创建一种机制,通过该机制在 UML 类图中区分元素和属性。这一点可以通过在 UML 图中创建称为 attribute 的特殊原型来实现。

3. 名称空间
名称空间是 XML 模式中一个非常重要的概念。它们表示将业务概念隔离到桶中。在 UML 图中,可以通过将 UML 模块保存在不同的包中来表示名称空间。

4. 多重性
我已经指出,UML 图中可以显示一些关联,如 OrderItem 之间的关联(一个 Order 可以包含几个 Item)。在 XML 模式中,maxOccursminOccurs 关键字用于表示一个元素的多重性关联,或者一个关联的多重性关联。

5. 派生类型
XML 模式允许通过扩展或限制来派生类型。通过扩展来进行继承是一种常见的面向对象设计,很容易通过在 UML 中显示抽象类来表达这种继承。抽象类是用斜体表示的(请参阅图 2)。然而,UML 中没有构造可以表示通过限制所进行的派生。

差距分析
很显然,UML 无法捕获 XML 模式中的所有丰富内容。这意味着,即便已经在 UML 中对 XML 模式进行了建模,您还是应该对这些模式进行手工扫描和调整。您应该解决的问题有:

  • 排序:在 XML 模式中,排序至关重要,而排序在 UML 的传统领域却没有任何用处。
  • 属性:如同前面在基础知识中所讨论的那样,在 UML 图中属性和子元素之间并没有清晰的界线。
  • 通过限制进行的派生:虽然 UML 可以显示抽象类及其实现,但传统 UML 图却没有正式的符号用来显示属于 XML 模式泛化技术的限制。
  • 键:键用来在 XML 模式中将文档链接在一起,但 UML 符号中却没有键表示。

差距分析针对的是 UML 符号在捕获 XML 模式所提供的全部功能时所显出的不足。UML 概要文件提供了一种通用的扩展机制,用于构建特殊领域中的 UML 模型。在 XML 模式设计领域中,UML 概要文件得到了扩展,以弥补基本 UML 模型中的差距。Dave Carlson 在他的著作 Modeling XML Applications with UML 中已经创建了这样一个 XSD 概要文件。

用构造型扩展 UML

差距分析列出了一些方面,在这些方面中 UML 不能清晰地捕获您想在 XML 模式中获得的内容,并且还决定扩展 UML 概要文件以弥补差距。UML 概要文件有三个关键项:构造型、标记值(特性)和约束。构造型允许您为 UML 基础类(如 Class)附加新的意义,构造型在 UML 图上表示为一个由双尖括号(<< >>)括起来的名称。

假定您有这样一种业务需求:税金还必须带有有关其货币种类的信息。换句话说,XML 看起来象下面这样:


            <tax currency=USD>7.60</tax>
            

在 XML 模式中,tax 元素带有属性 currency 以表示这一需求(请参阅清单 4)。为了在 UML 中创建相应的图,我们创建了两个新的构造型:用于表示 XML 模式属性的 <<XSDattribute>> 和用来表示双精度类型的 <<XSDsimpleType>>。我使用了 Dave Carlson 创建的对 UML 概要文件的 XSD 扩展。表示属性的扩展如下所示:


            <<XSDattribute>> on a UML attribute or association end
            use (prohibited | optional | required | fixed)
            

complexType Tax 基于 simpleType double,并且包含属性 currency。通过创建构造型,您现在已经在 UML 图中准确地捕获了新的业务需求,而且可以再次使用 UML 图来创建 XML 模式。正如我为元素 tax 设置了 currency 属性那样,我可以使用我的 <<XSDattribute>> 构造型来为 UML 图中的元素 weight 创建属性 unit。同样,需要为众多的 XML 模式构造创建 UML 扩展,以便在这两种框架之间提供完整的双向映射。

图 3. 带有构造型的 UML 图

相应的模式如下:

清单 5. ShippingOrder.xsd

            <?xml version="1.0" encoding="UTF-8"?>
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">
            <xs:include schemaLocation="DataTypes2.xsd"/>
            <xs:element name="shippingOrder">
            <xs:complexType>
            <xs:sequence>
            <xs:element name="shippingId"/>
            <xs:element name="origin" type="Origin"/>
            <xs:element name="destination" type="Destination"/>
            <xs:element name="order" type="Order"/>
            </xs:sequence>
            </xs:complexType>
            </xs:element>
            </xs:schema>
            
清单 6. DataTypes2.xsd

            <?xml version="1.0" encoding="UTF-8"?>
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">
            <xs:complexType name="Order">
            <xs:sequence>
            <xs:element name="item" type="Item" maxOccurs="unbounded"/>
            </xs:sequence>
            </xs:complexType>
            <xs:complexType name="Item">
            <xs:sequence>
            <xs:element name="description" type="xs:string"/>
            <xs:element name="weight" type="Weight"/>
            <xs:element name="tax" type="Tax"/>
            </xs:sequence>
            </xs:complexType>
            <xs:complexType name="Address" abstract="true">
            <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="street" type="xs:string"/>
            <xs:element name="city" type="xs:string"/>
            <xs:element name="country" type="xs:string"/>
            </xs:sequence>
            </xs:complexType>
            <xs:complexType name="Origin">
            <xs:complexContent>
            <xs:extension base="Address"/>
            </xs:complexContent>
            </xs:complexType>
            <xs:complexType name="Destination">
            <xs:complexContent>
            <xs:extension base="Address"/>
            </xs:complexContent>
            </xs:complexType>
            <xs:complexType name="Tax">
            <xs:simpleContent>
            <xs:extension base="xs:double">
            <xs:attribute name="currency" type="xs:string" use="required"/>
            </xs:extension>
            </xs:simpleContent>
            </xs:complexType>
            <xs:complexType name="Weight">
            <xs:simpleContent>
            <xs:extension base="xs:double">
            <xs:attribute name="unit" type="xs:double" use="required"/>
            </xs:extension>
            </xs:simpleContent>
            </xs:complexType>
            </xs:schema>
            

现在,XML 实例文档每次交换有关某一项的税费信息时都包含货币类型。

清单 7. ShippingOrder2.xml

            <?xml version="1.0" encoding="UTF-8"?>
            <shippingOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="C:\\schemas\\ShippingOrder.xsd">
            <shippingId>09887</shippingId>
            <origin>
            <name>Ayesha Malik</name>
            <street>100 Wall Street</street>
            <city>New York</city>
            <country>USA</country>
            </origin>
            <destination>
            <name>Mai Madar</name>
            <street>Liivalaia 33</street>
            <city>Tallinn</city>
            <country>Estonia</country>
            </destination>
            <order>
            <item>
            <description>Ten Strawberry Jam bottles</description>
            <weight unit="kg">3.14</weight>
            <tax currency="US">7.16</tax>
            </item>
            </order>
            </shippingOrder>
            

从 UML 模型生成 XML 模式

讨论了 UML 和 XML 模式之后,自然就要问:有没有一种将 UML 映射到 XML 模式的标准方法呢?如果有的话,那么就可能从 UML 图自动生成模式,供应商和开放源码工具可以提供这种功能。最好是,某个工具获取 UML 元模型并将它转换成 XML 模式。XML 元数据交换(XML Metadata Interchange, XMI)旨在能够在建模工具之间方便地交换元数据,而且可以进一步用来根据一组转换规则从 UML 图生成 XML DTD。

使用 XMI(XML 元数据交换)
XMI 是由与供应商无关的对象管理组织(Object Management Group, OMG)赞助的,它有三个主要标准:

  • XML:可扩展标记语言(eXtensible Markup Language),一种 W3C 标准
  • UML:统一建模语言(Unified Modeling Language),一种 OMG 建模标准
  • MOF:元对象工具(Meta Object Facility),一种 OMG 建模及元数据资源库标准

XMI 结合了这三种标准,因而代表了将元数据从一个库传送到另一个库的一种新方法。

我在文章中包含了一小段 XMI,目的是为了阐明当工具自动用 XML 生成元信息并随后将其转换成 XML 模式时后端所发生的事情。在清单 8 中,Foundation Core Model Element 是 ShippingOrder,您可以看到该 XMI(它十分冗长)编写了 UML 模型中所出现的每一片叶子。

清单 8. 由 hyperModel 为图 2 UML 模型(使用 ArgoUML 创建的)所生成的部分 XMI

            <Foundation.Core.ModelElement.name>ShippingOrder</Foundation.Core.ModelElement.name>
            <Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
            <Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
            <Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
            <Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
            

包括 TogetherJ、Rational Rose 和 ArgoUML 在内的大多数模型都可以创建 XMI 文件。我使用了 ArgoUML(它是开放源码的)来创建图 2 中的 UML 图。ArgoUML 创建了一个包含 XMI 文件的项目文件。当将它导入 hyperModel(由 Dave Carlson 开发,他最早讨论了如何使用 UML 对 XML 模式进行建模,并就该主题撰写了一本书)时,它生成了适当的模式构造。我下载了 hyperModel 的 30 天评估模型,不过您也可以选择其它工具。只要确保 XML 和 UML 模型的编码是正确的;例如,hyperModel 可以与 UML Model 1.3 一起使用。此外,任何时候都要检查生成的 XML 模式,以验证转换是准确的,尤其是在使用了新类型时更要如此。

由上面的 ArgoUML 生成并被放入 hyperModel 的 XMI 返回了清单 9 中的 XML 模式构造。通过仔细检查,可以肯定 hyperModel 捕获了图 2 中用 ArgoUML 创建的基本 UML 模型。由于 UML 处于单个包中,因此所生成的 XML 模式位于单个名称空间中。当在 ShippingOrderType 下进行调用时,诸如 Origin 之类的类型会被引用。

清单 9. 使用 XMI 生成的 ShippingOrder 元素类型

            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified">
            <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
            <!-- Class: ShippingOrderType  -->
            <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
            <xs:element name="ShippingOrder" type="ShippingOrderType"/>
            <xs:complexType name="ShippingOrderType">
            <xs:sequence>
            <xs:element name="shippingId" type="xs:int"/>
            <xs:element name="origin">
            <xs:complexType>
            <xs:sequence>
            <xs:element ref="Origin"/>
            </xs:sequence>
            </xs:complexType>
            </xs:element>
            <xs:element name="destination">
            <xs:complexType>
            <xs:sequence>
            <xs:element ref="Destination"/>
            </xs:sequence>
            </xs:complexType>
            </xs:element>
            <xs:element name="order">
            <xs:complexType>
            <xs:sequence>
            <xs:element ref="Order"/>
            </xs:sequence>
            </xs:complexType>
            </xs:element>
            </xs:sequence>
            </xs:complexType>
            </xs:schema>
            

结束语

许多大型集团公司 — 如 SWIFT,该公司为遍布全球的 7000 家金融机构提供贸易和结算的电子基础结构 — 正在使用 UML 到 XML 模式转换来设计他们的 XML 文档。UML 代表了对业务概念建模的最简单方法,尤其是当这些概念特定于某个领域的时候更是如此。人们很自然地想对这一过程进行延伸和自动化,以使转换显得整洁和完整。为此,我讨论了 XMI 的用法,还讨论了一些产品(如 hyperModel)从 XMI(用于描述 UML 元模型)生成 XML 模式的能力。不过,需要提醒读者的是,始终要细化并核实模型的有效性。尽管从 UML 完全映射到 XML 模式的能力还不是尽善尽美,但 UML 却是以面向对象方式对 XML 模式进行建模的良好开端。如果为自动生成 XML 模式而创建工具 — 既包括开放源码的也包括由供应商管理的 — 这一趋势继续下去,那么 UML 类图可能会成为将业务概念合并到 XML 词汇表的标准方法。

随着 XML 逐渐成为整个软件系统(从数据交换到 Web 服务消息到构建脚本描述)不可或缺的一部分,干净且简洁的 XML 模式建模方法已变得必不可少。UML 是一种经过试验和测试的用于面向对象系统的建模工具,作为设计 XML 模式的一种媒介,它对开发人员、业务分析人员和供应商都极具吸引力。我相信,随着业界和消费者开始使用 XML 开发他们自己的实体和服务,我们将会看到 UML 的使用不断普及。

参考资料

 

 

关于作者
AyeshaMalik 的照片Ayesha Malik 是 Object Machines 的一名高级软件顾问,她曾广泛参与了众多工业环境中大型 Java、XML 和 Web 服务系统的相关工作。她还在诸如 IBM developerWorks、XML.com 和 XML Developer Journal 等刊物上发表了很多有关软件开发方面的文章,并曾应邀在 O'Reilly Bioinformatics Conference 和 Web Services Edge Conference 上发表演讲。Ayesha 以优异成绩从哈佛大学获得了学士学位,同时她还拥有哥伦比亚大学的硕士学位,在哥伦比亚大学期间她学习了操作研究、应用数学和计算机科学。可以通过 ayesha.malik@objectmachines.com 与 Ayesha 联系。

原文转自:http://www.ltesting.net