内容


使用 IBM Rational Systems Developer 和 Rational Software Architect 实现 UML 与 C++ 的转换

同步修改模型和代码,实现由 UML 模型向 C++ 代码转换的迭代开发。

Comments

条件及过程概述

本文解释了作为一名 C++ 开发人员,如何在使用统一建模语言 UML 建模的时候,继续使用 C++ 数据结构进行设计。您只需掌握 UML、IBM® Rational® Software Architect 和 IBM® Rational® Systems Developer 的相关基本知识即可。

  1. 在 IBM Rational Systems Developer 创建一个简单的 UML 模型。
  2. 将一个 C++ 概要文件应用在模型上,这样,就可以在建模的过程中使用 C++ 的数据结构。
  3. 将 C++ 类型库导入模型,这样,就可以使用 C++ 基本类型。
  4. 生成代码。
  5. 在类中添加方法体。
  6. 另外提供一些小技巧,以便在重复进行转换时保存代码和模型的修改。

创建一个简单的 UML 模型

UML 概要文件是扩展 UML 的一个标准机制,所以对某些特定领域的建模可以在不增加 UML 负担的情况下进行。UML 的创始人不可能涉足到所有的应用领域,因而,他们明智地提供了扩展机制。

应用 C++ 概要文件

例如,要对某个 C++ 具体的元素建模,比如 structuniontypedef 等,您需要在 UML 模型上应用 C++ 概要文件。步骤如下:

  1. 确定您正处于 Modeling 透视图。
  2. 选中模型,然后单击 Properties 视图。
  3. Properties view 左侧,从列表中选择 Profiles
  4. 单击 Add Profile,在 Select Profile 对话框中 Deployed Profile 下方选择 C++ Transformation (如图1和2所示)。
图1. 应用 C++(CPP)概要文件
Figure 1. Steps in applying the C++ (CPP) profile
Figure 1. Steps in applying the C++ (CPP) profile
图2. 选择 C++ 概要文件
Figure 2. Selecting the C++ profile
Figure 2. Selecting the C++ profile

导入 C++ 类型库

UML 提供了一组预定义的类型,有 Boolean、Integer、String UnlimitedNatural。而大多数的编程语言,包括 C++,提供了更为丰富的基本类型。在 C++ 中建模的时候,您可能经常需要使用 C++ 预定义的基本类型(比如,将一个类型赋给某个属性、参数、操作返回类型,等)。下面讲述如何导入 C++ 模型库:

  1. Project Explorer 中右键单击 UML 模型。
  2. 如图3所示,选择 Import Model Library
图3. 导入 C++ 类型库
Importing C++ Type Library
Importing C++ Type Library
  1. 如图4所示,在 Import Model Library 的运行界面上,从下拉列表框中选择 C++ Types
图4. 选择要导入的 C++ 类型库
Selecting C++ Type Library
Selecting C++ Type Library

现在已经作好为 C++ 特定元素建模的准备了。请接着参看后面的示例。

创建一个简单的 UML 模型,car factory。

创建如图5所示的 UML 模型。创建的过程如下所示:

  • 这个示例模型中,BusCar 的基类是 Vehicle
  • BusCarVehicle 类被创建在一个名为 Vehicles 的 UML 包中。
  • 同样的,在名为 Parts 的包中,建立EngineWheels 类。
  • CarEngine 之间存在组合的关系。
  • 理论上, CarEngine 是不可分的,因为汽车需要引擎。
  • CarBusWheels 都有聚合的关系。
  • 本例中,轮胎可以没有汽车而存在,汽车可以没有轮胎而存在 -- 至少在组装的时候。
图5.一个简单的汽车工厂 UML 模型的示例
Figure 5. Simple UML model of a car factory used here as an example
Figure 5. Simple UML model of a car factory used here as an example

在模型中创建 C++ 元素

  1. 接下来,创建一个名为 Strategy 的 UML 包。
  2. Strategy,定义公共汽车的路线和起点。
    1. 创建一个名为 Route 的类,用来表示路线;一个名为 Address 的类,用来表示地址,比如公共汽车路线的起点。
    2. Address 需要是 C++ struct 元素而不是普通的类。
  3. 为 UML 模型指定每个公共汽车的路线。如图6所示,您可以为 Vehicles 包中的 Bus 类和 Route 类之间设置聚合关系。
  4. 起始点是路线的一个属性。所以,为 Route 类增加一个类型为 Address,名称为 startingPoint 的属性。
图6. 名为 Strategy UML 包的内容
Figure 6. Contents of the new UML package called Strategy
Figure 6. Contents of the new UML package called Strategy

在图6中,请注意 Address 是 <<cpp_struct>>类。创建的步骤如下:

  1. 创建一个 UML 类,命名为 Address
  2. cpp_struct 原型应用给新建立的类。
    1. 将一个原型应用给 UML 元素,转到 Properties 视图。
    2. 如图7所示,从左侧的列表中选择 Stereotypes,然后单击 Apply Stereotypes
图7. 应用一个原型
Figure 7. Applying          a stereotype
Figure 7. Applying a stereotype
  1. 从该元素可用的原型列表中选择 cpp_struct。同时,也可以留意一下其它的选择,以备日后参考。

您很快就能发现,将这个模型转换成代码的时候,带有<<cpp_struct>>原型的 Address 类将会生成一个 struct 元素,而不是一个类。

配置转换并生成代码

在由模型生成 C++ 代码之前,需要通过创建转换配置来设置相应的参数。

创建转换配置

步骤如下:

  1. 单击 File > New > Others,然后选择 Transformations 文件夹中的 transformation configuration
  2. New Transform Configuration 向导中,指定配置文件名,此处命名为 tc1
  3. 选择 transformation typeproject
    1. 展开 IBM Rational Transformations 列表,然后选择转换类型 UML to C++
    2. 本练习中,使用已有 UML 模型项目来保存转换配置文件。
  4. 单击 Next,继续进行后面的步骤。
  5. Source and Target 选项卡中:
    1. Source:选择 UML 模型。
    2. Target:创建一个新的 C++ 项目。
  6. 请确定 sourcetarget 都是选中的,然后单击 Finish

注:
如果需要,您可以再对转换配置进行修改。

生成代码

之后的步骤就比较简单了。

  1. 进行到现在,您已经完成了大部分比较难的工作,接下来,只需右键单击 tc1.tc,然后从弹出式菜单中选择 Transform > UML to C++,就可以在选定的项目中生成代码。
  2. 看一下 Route 类生成的代码。如列表1所示,它包括 startingPointendingPoint 属性,以及 getFare() 方法。
列表1. Route 类生成的代码文件 Route.h
#ifndef ROUTE_H
#define ROUTE_H
//Begin section for file Route.h
//TODO: Add definitions that you want preserved
//End section for file Route.h

struct Address;

//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
class Route
{

    private:
  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_Hk7qMACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        float runningCost;

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_hKd58ACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        float expectedProfit;

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_ieiw8ACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        Address * startingPoint;

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_jkEOkACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        Address * endingPoint;
    public:

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_kawmAACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"

        float getFare()const ;

};  //end Class Route

#endif

如列表2所示, getFare 方法的默认内容已经生成。

列表2. Route.cpp
#include "Route.h"
//Begin section for file Route.cpp
//TODO: Add definitions that you want preserved
//End section for file Route.cpp


float Route::getFare() const 
{
    //TODO Auto-generated method stub
    return 0;
}

修改代码

请注意,默认生成的内容一般不能够直接使用,因为 fare 总是 0 (zero),而这并不是一个有利的业务!所以需要将 getFare 方法的内容用列表3来代替。

列表3. Route.cpp
float Route::getFare() const 
{
    // Calcualte the fare
    return runningCost * expectedProfit;
}

开发模型并再次运行转换

现在,在UML模型中为 Route 类添加另一个名为 print_disclaimer() 的方法。

  1. 设置返回类型为 String
  2. 请注意,我们已为 getFare 方法添加内容,修改了Route.cpp文件。
  3. 使用相同的配置 (tc1.tc > Transformation > UML to C++)运行转换。
  4. 选择目标文件自动更新(默认选项)。

现在,一起来看看更新的代码(列表4)。

列表4. 更新的 Route.cpp
#include "Route.h"
//Begin section for file Route.cpp
//TODO: Add definitions that you want preserved
//End section for file Route.cpp


float Route::getFare() const 
{
    // Calcualte the fare
    return runningCost * expectedProfit;
}

//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
const char * Route::print_disclaimer() 
{
    //TODO Auto-generated method stub
    return 0;
}

请注意,修改的 getFare() 方法体已被保存。同时,模型中新添加的 print_disclaimer 方法已在 Route.h 和 Route.cpp 文件中生成新的代码。这样,您可以继续在代码中执行方法,同样地,可以对模型作增量修改。这在模型驱动迭代开发中相当有用的。

将 include 声明添加到保存节中。

print_disclaimer 方法体的代码如图5所示。请注意,我们使用了 cout 操作符,但 C++ 不能够识别。然而,代码是否能够正确解析,这是相当重要的,所以当转换再次执行的时候,应当将代码结构和方法体保存下来。如果想使这段代码可编译,您需要在 cpp 文件中添加 #include <iostream>using namespace std;。当重复执行 UML 与 C++ 转换的时候,这些声明将会被保存下来。把这些声明插入到以下两条注释之间:

//Begin section for file Route.cpp
//End section for file Route.cpp

您添加到这个节中的内容将一字不漏地保存下来, 并且不需要 C++ 转换解析。

列表5. Route.cpp
#include "Route.h"
//Begin section for file Route.cpp
#include <iostream>
using namespace std;
//End section for file Route.cpp


float Route::getFare() const 
{
    // Calcualte the fare
    return runningCost * expectedProfit;
}

//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
const char * Route::print_disclaimer() 
{
    const char *s = "No Refund once the ticket is purchased\n";
    cout << s;
    return s;
}

下载:

  • UML 模型和 C++ 项目示例:选择 File > Import,然后按照 Import Existing Projects into Workspace 向导的提示操作,就可以将项目导入到 Eclipse 工作空间。

小结

本文讲述了使用 Rational Systems Developer 创建 UML model,然后生成 C++ 代码的基本步骤,以及保持代码与模型同步的方法。想要了解更多的信息,请参阅相关的链接资源。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=248280
ArticleTitle=使用 IBM Rational Systems Developer 和 Rational Software Architect 实现 UML 与 C++ 的转换
publish-date=08132007