扩展转换您可能有很多种理由。例如,您想要向方法添加自动生成的文件,该方法列出了参数以及返回种类。或者您想要改变转换产生的默认方法主体。不管是哪种情况,扩展转换都能帮助您去产生自己的,自定义的资源。
UML 到 C++ 的转换在 V7.0 中得到完全的重新设计。以前在 V6 中,转换在完成一个 UML 模型后,直接将其写进输出缓冲器中,该缓冲器最终将删去这些作为 C++ 文件的内容 。因此您需要决定,在缓冲器中写进什么内容。
在 V7.0 中,转换在完成一个 UML 模型后,将构建一个 C++ 抽象语法树状图,它只不过是一个 EMF 模型 。然后转换使用 JET2 来将模型转换成 C++ 资源。 您需要利用该树状图,来以任何方式编辑生成的代码。因此在这种情况下,您需要有一些该中级模型的知识,特别是一些关于参加了 C++ 代码生成的核心部分的知识,例如,这些部分有类,结构联合,枚举,方法以及属性 。
模型类隶属于一种叫做 com.ibm.xtools.cpp.model 的插件。模型的 Javadoc™工具是作为文件的一个附属物,如图 1 中的图表所示。
图 1. UML 到 C++ 的转换
在分开的文件(参见下载部分)中,本篇文章所举的范例,教您打下了扩展 Rational Software Architect v7 中 C++ 转换的基础。如果您已安装了该软件,您只需在您的插件目录中提取出范例,重新启动 Rational Software Architect,并运行以下转换:
- 范例 1 将默认的方法主体,改变成了您所想要的。
- 范例 2 在每个方法之前添加了一个注释。
- 范例 3 在每个属性之前添加了一个注释。
本篇文章只带您学习范例 1 的应用。范例 2 与范例 3 相似,您可以自己去探索它们。
UML 到 C++ 转换可通过 com.ibm.xtools.transform.core.transformationExtensions 扩展点得以扩展。该扩展点让您能够添加规则,内容提取器,或者向一个已存在转换的转换 ,例如 UML 到 C++ 的转换。对于一个转换而言,以下项目可被定义:
- Property:转换的新属性
- RuleDefinition:扩展当前行为的新规则
- ExtractorDefinition:制作模型的新内容提取器
- TransformDefinition:新转换(内含提取器以及规则)
- ExtendTransform:向一个已存在转换添加新规则,提取器或者转换
通过添加新规则,本篇文章致力于扩展从 UML 到 C++ 的转换,因为大多数情况下,这一般是您最需要做的。
为了向转换添加一个新规则,您需要完成三件事:
- 通过使用
RuleDefinition来定义规则。 - 通过使用
ExtendTransform来扩展转换以插入新规则。 - 定义代表规则的类。
图 2 是在生成的代码中,添加一条规则,以改变默认的方法主体后,您的 XML 插件外观的快照。特别注意该行:
com.ibm.xtools.transform.uml2.cpp.bodyextension.CPPMethodBodyRule (AddRule) |
图 2. 在添加一条规则后的 XML 插件
列表 1 向您显示了 RuleDefinition 是什么样的。
列表 1. RuleDefinition 范例
<RuleDefinition
class="com.ibm.xtools.transform.uml2.cpp.bodyextension.CPPMethodBodyRule"
description="Adds a user defined body to a method"
id="com.ibm.xtools.transform.uml2.cpp.bodyextension.CPPMethodBodyRule"
name="C++ Method Body Rule"/>
|
正如您所猜到的一样,class name 参考了定义规则的实际类。属性 ID 单独识别了转换框架的规则。属性 name 与 description 只是:您所选择规则的名字,以及它的功能的描述。
在您定义新规则以后,您需要在合适的转换中合适的位置上插入该转换 ,通过使用如列表 2 所示的 ExtendTransform .方法,您可以做到这点。当然,appropriate transform 部分很容易理解。但是 appropriate place 需要一些注释,这样我们就能很快理解它了。
列表 2. ExtendTransform 范例
<ExtendTransform targetTransform=
"com.ibm.xtools.transform.uml2.cpp.ClassOperationTransform">
<AddRule
id="com.ibm.xtools.transform.uml2.cpp.bodyextension.CPPMethodBodyRule"
index="1">
</AddRule>
</ExtendTransform>
|
在该范例中,方法主体规则需要进入一个 Operation 转换。我们已经选择了 ClassOperationTransform,这意味着,该新规则只能影响在 UML 类或者固定的 UML 类中,定义的操作的行为,例如,在 UML 界面上定义的操作。注意,该规则的 ID ,与您在使用 RuleDefinition 来定义新规则时使用的 ID 相对应。
另一个需要注意的重要事项是 index,它决定了在您插入的转换链中,您的规则将链接到哪里。这非常重要,因为这决定了,对已转换的元素进行了什么类型的处理(在本例中,是一次 UML 操作)。它还能够影响继承规则的处理,因为通过改变转换的目标,您的规则可能影响到转换的行为,这一点您将在下一段落中看到。
在这种情况下,您插入的规则,是作为 ClassOperationTransform 中的第二规则(indexing 开始于 0)。 在下载文件中, 我们已经给出了每一个转换,以及规则链接情况的概述。在这里就可以说明,该规则什么时候起效,在上面提到过的抽象语法树状结构中,已经创建了一个目标 C++ 操作。这将传递给您的规则,并作为您的转换目标,而且这是您需要掌控的数据结构,以得到您想要的操作。
定义一个新规则的最后一步,是定义一个代表该规则的类。在这种情况下,它代表了 CPPMethodBodyRule 类。
列表 3 是一个显示如何执行规则类的代码片段。
列表 3. 执行规则类的范例
package com.ibm.xtools.transform.uml2.cpp.bodyextension;
import com.ibm.xtools.cpp.model.CPPOwnedMethod;
import com.ibm.xtools.transform.core.AbstractRule;
import com.ibm.xtools.transform.core.ITransformContext;
public class CPPMethodBodyRule extends AbstractRule {
public boolean canAccept(ITransformContext context) {
Object object = context.getTarget();
if (! (object instanceof CPPOwnedMethod))
{
//this can happen if the method was not processed.
//Then the target container would contain
//the parent of the method.
return false;
}
return true;
}
protected Object createTarget(ITransformContext context)
throws Exception {
System.out.println("Invoking extension");
String newBody = new String ("//User defined body");
Object object = context.getTarget();
CPPOwnedMethod method = (CPPOwnedMethod)object;
method.setMethodBody(newBody);
return method;
}
}
|
所有的规则类必须扩展转换框架定义的 AbstractRule 类。它同样应该超越 canAccept 与 createTarget 方法。
方法 canAccept 基本上决定了,该规则是否能够接受传递给它的转换内容。转换内容正如它声称的那样:它含有哪个元素被转换(即 ITransformContext.SOURCE 对象),它将被转换成什么(即 ITransformContext.TARGET 对象),以及转换准备将转换对象置于何处(即 ITransformContext.TARGET_CONTAINER 对象)等相关信息的内容。
在本例中,正如您在前面章节中看到的那样,规则被插入 ClassOperationTransform,而且它的转换源是一次 UML 操作。但是,规则不应该为该转换不准备处理的操作而运行。例如,如果您在一个模板例子,或匿名联合体中错误地为操作建模,那么这样的操作应该被弃除。在这里,方法 canAccept 检查 CPPOwnedMethod 种类的目标对象是否为操作创建了,这意味着该操作能够被安全地处理。(稍后更多关于 CPPOwnedMethod ,那时我们将讨论 C++ 模型)。
第二个方法是 createTarget 方法,在这里您要更改产生的目标,这就是您要着手进行的。这里,例如,方法主体被设置成您所选择的字符串。注意,在 canAccept 方法中,您已经检查以确定,只当目标是 CPPOwnedMethod 时该规则才被激活。因此,在转换期间访问 canAccept 后的 createTarget 方法中,您可以放心地假设,目标确实是 CPPOwnedMethod。
提示:
确保您从 createTarget 方法中返回了修改后的 CPPOwnedMethod。
如果想查看另外两个例子,并得到更多有用信息,您可以下载与本篇文章相配套的 PDF 文件。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| Javadoc | ExtendingUML2Cpp-RSA-Appendix.pdf | 108KB | HTTP |
学习
- 您可以参阅本文在 developerWorks 全球网站上的 英文原文。
- 访问 developerWorks 上的 Rational 软件专区,了解有关 Rational 软件交付平台产品的技术资源和最佳实践。
- 订阅 Rational Edge 中文版,获得了解高效软件开发背后概念的文章。
- 订阅 IBM developerWorks 时事通讯,获得有关最佳的 developerWorks 教程、文章、下载、社区活动、网络广播和事件的每周更新。
- 浏览 技术书店,获得有关这些和其它技术主题的书籍。
获得产品和技术
-
下载 Rational Software Architect 试用版。
- 下载 IBM Rational 软件的试用版。
- 下载这些 IBM 产品评估版,并着手使用来自于 DB2®,Lotus®,Tivoli®,以及 WebSphere® 的应用程序开发工具和中间件产品。
讨论
- 查看 developerWorks 博客,并加入 developerWorks 社区。
-
Rational Software Architect,Data Architect,Software Modeler,Application Developer 和 Web Developer 讨论区:询问有关 Rational Software Architect 的问题。

