UML 是一個通用的語言。使用 IBM? Rational Software Architect 和 IBM Rational Systems Developer,您可以實現由 UML 模型向 C++ 的轉換。這篇文章討論了如何更好地控制由 UML 向 C++ 轉換而生成的 C++ 代碼。文章分成幾個章節,各部分相對獨立,分別介紹了一種技巧。您可以根據需要選讀,而不必遵循特定的次序。
應用 C++ Transformation 概要文件以實現 C++ 結構的建模 在統一建模語言 UML 和某特定領域之間建立聯系的標准方法是使用 UML Profile(UML 概要文件)。UML 概要文件可以為已有 UML 元素定義附加語義和特性,例如類、操作等。建模 C++ 特定元素的時候,如 結構體、聯合體、名字空間 等,需要用到 UML 概要文件。在 Rational Software Architect 和 Rational Systems Developer 使用 C++ Transformation profile 實現 UML 向 C++ 的轉換,這個概要文件在 UML 模型中的應用如下所示。
在 Project EXPlorer 中選擇概要文件將要應用的 UML 模型。
在 Project Explorer 保持模型是選中狀態,轉換到 Properties View,單擊 Profiles 選項卡。
如圖1所示,單擊 Add Profile 按鈕。
圖1. 將 UML 運用到 C++ Transformation 概要文件
如圖2所示,從 Deployed Profile 下拉列表框中選擇 C++ Transformation。
圖2. 選擇 C++ Transformation
導入 C++ 類型庫 UML 提供了一組已定義好的類型,有 Boolean, Integer, String 和 UnlimitedNatural。而大多數的編程語言,包括C++,提供了更為豐富的基本類型。在 C++ 中建模的時候,您可能經常需要使用 C++ 預定義的原始類型(比如,將一個類型賦給某個屬性、參數、操作返回類型,等)。To import the C++ model library that is shipped with the C++ Transform,在 Project Explorer 中右鍵單擊UML模型,然後選擇 Import Model Library,如下圖3所示。
圖3. 導入 C++ 類型庫
如圖4所示,從 Deployed Library 列表中選擇 C++ Types。
圖4. 導入 C++ Type Library
在模型中創建 C++ 名字空間 本章節講述如何在 UML 模型中為 C++ 名字空間建模。在 C++ 中創建一個名字空間時,需要將 cpp_namespace 原型應用在 UML 包。在 UML 向 C++ 轉換的過程中,一個 UML 包默認被映射成一個文件夾。假如想要將 UML 包映射成名字空間,而不是文件夾,那麼,您需要應用 cpp_namespace 原型,然後設置 NamespaceName 的屬性,使其與指定的名字空間相關聯。這個 stereotyped UML 包下所有的 類、結構、枚舉 (以及其它)生成代碼之後,都將包括在這個名字空間中。
您可能想知道為什麼名字空間不能直接采用 stereotyped 包的名稱。這是為了支持 C++ 匿名的名字空間建模。所以,假如您將 NamespaceName 屬性設置為空,那麼,該名字空間就會被認為是匿名的。
建模 C++ typedefs 要建模 C++ typedef,需要創建一個 UML 類並在其上應用 cpp_typdef 原型。該原型提供了以下屬性/值:
arrayDimensions
ImplementationType
qualifier
想要創建一個類型定義,比如 typedef int const IntMatrix100_20_t [10][20];,首先創建一個 UML 類 IntMatrix100_20_t,然後應用 cpp_typedef 原型。如圖5所示,設置該原型的屬性。
圖5. 建立一個 C++ 類型定義
在將 typedef 定義與概要文件中提供的屬性相關聯的過程中,您可能會考慮到以下方式: typedef
創建多維數組屬性
在本節中,您將會學到如何為一個大小為[10][20][30]的三維數組定義屬性。在 Project Explorer 中選擇需要賦給多維數組的屬性。在 Properties 視圖中,單擊 Stereotypes 選項卡,然後單擊 Apply Stereotypes 按鈕,並選擇 cpp_type 原型。這個原型提供了以下屬性/值:
arrayDimensions
InitializerKind
isAuto
isMutable
isRegister
isVolatile
qualifier
如圖6所示,在 arrayDimensions Value 處,指定 [10][20][30]。這樣,在源代碼中就會生成維度屬性為[10][20][30]的數組。
圖6. 設置 Multidimensional Attributes
將一個方法的形參設置為常量
這個技巧的原理同上(前面提到的定義多維數組)。在 Project Explorer 中選擇預備設置為 const 的參數。單擊 Apply Stereotypes 按鈕並選擇 cpp_type 原型。該類型提供了以下屬性/值:
arrayDimensions
InitializerKind
isAuto
isMutable
isRegister
isVolatile
qualifier
這些屬性都是可能用得到的,但暫時只介紹 qualifier 屬性。在 qualifier 的 Value 處,輸入 const (如 圖5 所示)。這樣,當轉換執行的時候,將在源代碼中為選定的參數生成帶有常量修飾符的函數簽名。
注: 請確保輸入的值是有效的。假如輸入錯誤,則會導致編譯失敗,您需要在再次運行轉換之前修正錯誤。
另外,cpp_type 原型也適用於類的屬性。但是,生成一個常量屬性的更簡單的方法是將屬性標明為 Read Only。
將整個方法聲明為常量
假設您想要將一個方法聲明為常量,以便在生成的代碼中帶有 const 要害字: )int Operation1(MyType Parameter1 const;。您需要在 Properties 視圖的 General 選項卡中選擇 Query 修飾符。這裡,不需要應用原型。
圖7. 創建一個常量方法
給一個方法增加異常處理
Exceptions 是 UML 中重要的類,它在建模過程中不需要使用概要文件。為了簡化並推廣建模, UML to C++ Transformation 使用了普遍適用的 UML 屬性,而不是概要文件。要生成一個 throw 子句,比如 int Operation1() throw ( MyType);,您首先需要為操作創建一個參數,然後設置其 Is Exception 屬性為 true。
在轉換過程中,參數名是可以被忽略的,但最好還是定義一個合適的名稱(以備異常拋出時正確提示)。圖8顯示了如何將參數的 Is Exception 屬性設置為 true。
圖8. 設置某方法的 throw 類型
控制生成的代碼中的 include 聲明
UML to C++ Transformation 可以自動生成恰當的 include 聲明。 然而,您可能想要根據需要生成更合適的 include 聲明。例如,已確定要使用本地方法體的某個類型變量,因此,想要生成包括在文件中的 include 聲明建模時,您可能需要創建兩個類之間的依靠,然後將 cpp_dependency 原型應用在依靠。這個原型和名為 IsInclusionInHeader 的屬性一起出現,該屬性值默認為 false。假如需要將 include 聲明包括在生成的文件體中,請將這個屬性值設為 false;假如需要將 include 聲明生成在頭文件中,那麼,可以不設置依靠的 cpp_dependency 原型,也可以應用原型並將 IsInclusionInHeader 屬性值設為 true。
使用文件級別得重用保護部分
假如要使用標准庫的類型,或者一些源代碼的其它庫,您需要在模型中將這些類型設置為普通的字符串。例如,假如要將一個屬性聲明為整型,您需要在模型中指定它的類型為 vector 轉換時,將會把這些類型當成原始類型,並且不會生成任何 include 聲明或其它聲明。因此,您需要將這些都明確地包含進源文件中。
比如,對於 vector 類型,您應當明確地將 include 聲明放置在源代碼中,比如 #include 。如列表1所示,在應用 UML 向 C++ 的轉換過程中,每個生成的文件都一字不漏地包含一些段落的內容。請注重 //TODO: Add definitions that you want preserved。您添加到 Begin section 和 End section 中的任何內容都將被保存下來。請在此處添加聲明,比如這裡的 #include 。
列表1. 類 Car 所生成代碼
#ifndef CLASS1_H
#define CLASS1_H
//Begin section for file Class1.h
//TODO: Add definitions that you want preserved
//End section for file Class1.h
#include "MyType.h"
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
class Class1
{
//Begin section for Class1
//TODO: Add attributes that you want preserved
//End section for Class1
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int Operation1()const throw ( MyType);
}; //end Class Class1
#endif
刪除類級別得重用保護部分
請注重,在前面列表1的代碼中,有一段 //Begin section for Class1 ... //End section for Class1 ,您可以將 C++ 中所有不能建模的聲明保存在這裡。返回 UML to C++ Transformation 時,不會覆蓋這段聲明。假如您不需要這一聲明出現在生成的代碼中,可以選擇刪除。但是,刪除之後,即使再次運行 UML to C++ Transformation,這些聲明也不會重新生成。
假如不需要,可以刪除如列表2所示的段落,那麼刪除之後不能夠重新生成。假使想要恢復這些聲明,您就需要手動地進行插入。
列表2. 類 Car 生成的代碼
...
//Begin section for Class1
//TODO: Add attributes that you want preserved
//End section for Class1
...
不修改 UML 模型的情況下,改變生成包的名稱。
要改變包的名稱,請雙擊打開轉換配置文件。如圖9所示,單擊 Mapping 選項卡,選擇 Enable mapping。
圖9. 使用映射模型
單擊 New 按鈕,創建一個默認的映射模型,賦給一個適合的名稱。單擊 Edit Mapping 按鈕,出現如圖10所示的對話框。
圖10. 編輯映射模型
假使您正進行到如圖11所示的 UML 模型。假如沒有映射模型,那麼 Date 類將會生成在一個名為 Package1 的文件夾內。然而,假如您想要將 Package1 生成為 Folder1,那麼需要使用映射模型。浏覽映射模型,找到 Package1,然後在向導底端的 Mapped Name 編輯框輸入 Folder1。這樣,在生成的代碼中,Date 類就生成在名為 Folder1 的文件夾內了。
圖11. 您正在操作的 UML 模型
在同一個文件裡生成多個類
在映射模型中,假如您想將一個 UML 類映射為另外的名稱,您需要改變其將要生成文件的名稱,而不是類名。默認情況下,頂級類將生成一個與類名相同名稱的文件。因此,對於一個名為 MyClass 的 UML 類,UML 向 C++ 的轉換將會生成文件 MyClass.h 和 MyClass.cpp。
但是,在使用映射模型的時候,您也可以選擇生成與原類名不同名稱的文件。比如,您可以改變 UML 包的名稱,生成另外命名的文件夾;您也可以將一個 UML 類映射為另外命名的文件。類的名稱並不受映射模型的影響。因此,要想在一個文件中生成多個類,您所需要做的僅僅是在映射模型中為它們指定相同的目標名稱。