• 沒有找到結果。

生成含 Annotation 程式碼

3.  Design Pattern 資訊儲存與轉換

3.5  生成含 Annotation 程式碼

藉由上述的修改,UML 在使用者的編輯下應能正確的包含 design pattern 資 訊。為了產生包含annotation 的框架程式碼,我們將再修改 Netbeans 的兩個部分,

分別是 ClassInfo 產生的流程能夠擷取 pattern node 的 design pattern 資訊、以及 FreeMarker 所參考的樣板文件必須加入 annotation 的欄位。ClassInfo 的資訊將用於 產生 java source code,因此他必須有記錄 design pattern 資訊的欄位和記錄 annotation 名稱的欄位。因為我們的設計是利用 annotation 來儲存與表示 design

25

pattern 資訊,兩者將會是同樣的內容,因此 ClassInfo 當中僅有記錄 annotation 的 欄位,而此欄位在我們的設計下僅用於記錄design pattern 資訊。

3.5.1 ClassInfo 的修改

ClassInfo 是在 generate code 模組的流程中產生的一個物件,NetBeans 會針對 每個類別或interface 的 UML 將會產生一個相對應的 ClassInfo 物件,ClassInfo 紀 錄類別資訊的方式很簡易,僅利用String 儲存。之前的 UML 編輯已經能夠描述夠 多設計資訊,ClassInfo 主要的功能是做一個整合,讓 FreeMarker 能夠快速的取得 名稱的訊息。

我們的目的在於產生 annotation 的內容,因此在 ClassInfo 建立一個紀錄 annotation 名稱的 String 欄位。在產生 ClassInfo 的過程,我們必須加入一個分析 XML pattern node 的流程,這個流程將會從 UML 的 pattern node 當中獲得 design pattern 資訊的內容。同樣的步驟也會套用在產生 MethodInfo 與 MemberInfo 的流程 中。因為 FreeMarker 不能直接參照 field,必須加入回傳 annotation 內容的方法,

以供Freemarker 產生 source code 時,填入 annotation 名稱。

我們雖然可以藉由annotation 套件的設計,來分辨 annotation 與它所描述的元 件所屬的design pattern。但為了處理上的迅速,我們在 ClassInfo 的 annotation 加 上了design pattern 名稱。實際的 annotation 內容將會如下:

¾ @ “design pattern 名稱”_ “annotation 名稱”

實際的案例如表 3-11 的程式碼所示,該介面(interface)是 state pattern 中的 state 角色,因此所顯示的 annotation 為 “@State_State”。而這項修改將不會套用於 MethodInfo 與 MemberInfo 的流程中,因為 method 和 field 可以靠類別或介面來分 辨pattern 的類型。

26

3.5.2 FreeMarker 樣板文件的修改

FreeMarker 的樣板文件可以直接使用 ClassInfo 物件所具有的方法。Java annotation 是標記在欲描述的 classes、interfaces、methods、variables 的前頭,因此 我們追尋了樣板文件中產生 classes、interfaces、methods、variables 內文的部分,

在這之前加上取得annotation 名稱的方法(如表 3-6)。而想要在 FreeMarker 樣板文 件中要ClassInfo 的方法,必須用${method}的字串來引用。我們將呼叫的方法放在 正確的位置,利用這樣的修改來使 FreeMarker 產生 Java source code 能夠包含 annotation。

<#--

NormalClassDeclaration -->

<#import "DeclLib.ftl" as lib />

<#macro NormalClassDeclaration classInfo nestingLevel

>

<@lib.TypeDeclarationComment classInfo nestingLevel />

${classInfo.getImportName()}

${classInfo.getPatternName()}

<@lib.ident nestingLevel /><@lib.compress single_line=true >

<@lib.TypeDeclarationModifiers classInfo /> class ${classInfo.getShortClassName()}

<@lib.TypeDeclarationTypeParameters classInfo /> <@lib.NormalClassExtends classInfo />

<@lib.ClassImplements classInfo /></@lib.compress> {

<@lib.ClassBodyDeclaration classInfo nestingLevel+1 />

<@lib.ident nestingLevel />}

</#macro>

表 3-9 : 修改後的 class 樣板內文

27

3.5.3 Annotation 套件和宣告

Java annotation 在文法的使用上,必須先經過宣告和引用,才能夠利用 annotation 來描述一個元件。因為宣告和引用方法在格式上固定,所以我們在 generate code 模組的流程中加入自動創建宣告和引用的功能。

在generate code 模組的流程,我們可以藉由 ClassInfo 的資訊得知打算產生的 annotation 內容,因此我們利用建立檔案的方法產生 annotation 的宣告文件(參見表 3-10),並且利用 package 來管理這些宣告文件,我們定義以下的名稱:

¾ NTU.Annotation.DesignPattern. “pattern的名稱

” ;

¾ NTU.Annotation.DesignPattern. “pattern的名稱

” .method;

¾ NTU.Annotation.DesignPattern. “pattern的名稱

” .field;

這些套件來儲存相對應的annotation 定義文件(圖 3-6 是實際範例)。我們必須 利用這樣多層次的方式來儲存annotation 定義文件,來解決 design pattern 定義的內 容名稱重複的情形;利用套件名稱來獲得更詳細design pattern 元件內容,並且利 用自動產生檔案的方法來省去使用者負擔。

圖 3-6 : annotation 定義所存放的 package

package NTU.Annotation.DesignPattern.State;

import java.lang.annotation.*;

/* auto generate code */

@Retention(value = RetentionPolicy.SOURCE) public @interface State_State {}

表 3-10 : annotation 的宣告文件

我們再產生的Java 框架程式碼使用 annotation 描述元件,為了編譯的正確必

28

須引用annotation 的宣告,這樣的宣告內容同樣的在 generate code 模組的流程自動 產生。我們擷取一份source code 當中使用到的 annotation 內容,將引用的程式語 言加入到ClassInfo 的欄位,因此同樣的利用 3.5.1 的方式修改 ClassInfo 的內容和 3.5.2 的方式修改 FreeMarker 樣板文件,便可在 Java 框架程式碼上加入引用 annotation 的宣告。