• 沒有找到結果。

J2ME Transformation Pattern

Chapter 6 Mobile Application Transformation

6.3 J2ME Transformation Pattern

在本轉換樣式(transformation pattern)中,要說明的是:將 PUML 文件轉換成 J2ME MIDP 程式碼的轉換規則,以及將 PGML 文件轉換成 J2ME MIDP 程式的 轉換規則。以上兩種轉換規則合稱J2ME Transformation Pattern。

使用PUML / PGML 所描述的行動應用程式,經過轉換成 J2ME MIDP 程式碼之 後,所有轉換出來的.class,都必須在同個 package 下(即在同一個資料夾下)。

A. PUML 轉成 J2ME MIDP 的轉換規則

接下來以條例式的方式,列出PUML 轉成 J2ME MIDP 的轉換規則。

z 一份 PUML 文件轉換成相對應的 J2ME MIDP 之後,會產生兩種類型的 class,以及一個 interface。轉換系統會產生一個 interface –

BMngr_Interface。<user-interface>會對應到一個繼承自 MIDlet 的 class,且此 class 必須實作轉換系統所產生的 BMngr_Interface interface (extends MIDlet implements BMngr_Interface)。每個<board>會對應到一 個繼承自 Form 並實做 CommandListener interface 的 class (extends Form implements CommandListener)。

z BMngr_Interface interface 有兩個 method 需要被實做(implementation)。

一個是

changeBoard(String boardName) method,透過參數傳遞,指出

所要切換的使用者介面,並在此method 被執行之後,畫面切換到所指 定的使用者介面。

另一個是

getBoard(String boardName) method,透過參數傳遞,指出所

要取得的使用者介面,並在此method 被執行之後,可以取得代表該使 用者介面的變數,可以對此變數作操作,例如:更改該使用者介面中的,

某個使用者介面元件的狀態值。

interface BMngr_Interface {

public void changeBoard(String boardName);

public Displayable getBoard(String boardName);

}

[圖 6-3 BMngr_Interface interface]

z 將一份 PUML 文件做轉換之後,只產生一份.java 檔,裡頭包含了所有 的 class(第 1 點所提到的兩種 class),以及 BMngr_Interface 這個 interface。在這份.java 檔中:

a) <user-interface>所對應的 class(即繼承 MIDlet 的 class),必須為 main class。

b) main class 必須是 public class,其他的 class、interface 不使用 public 這個關鍵字。也就是說,在同一份.java 檔中的所有 class 們,僅能 有一個class 是 public,且 interface 不能是 public。

c) .java 檔的檔名要跟 main class 的 class name 一樣。

z 在轉換成 J2ME MIDP 程式碼之後,<user-interface> element 會對應到一 個繼承自MIDlet 的 class,且該 class 實作轉換系統產生的一個 interface – BMngr_Interface 。 <user-interface> 所 對 應 到 的 class 名 稱 為 : BMngr_@user-interfaceName。這裡的@user-interfaceName 指的是

<user-interface>的 attribute – name 的屬性值。

z 在轉換成 J2ME MIDP 程式碼之後,<board> element 會對應到一個繼承 自 Form 的 class,且該 class 實作一個 interface – CommandListener。

<board> 所 對 應 到 的 class 名 稱 為 : B_@boardName 。 這 裡 的

@boardName 指的是<board>的 attribute – name 的屬性值。

z 在 BMngr_@user-interfaceName class 中:

a) 在 PUML 文件中描述宣告的 global logic object 所對應的 class,在轉 換 成 J2ME MIDP 程 式 碼 之 後 , 必 須 在 此 BMngr_@user-interfaceName class 中,一開始就被宣告並產生物件 出來(使用 new 這個關鍵字),並且對外開放(使用 public 這個關鍵 字)。由於邏輯物件(logic object)對應的 class,其建構子(constructor) 不需要參數,所以在產生物件的過程中,不需給與初始值。

[例如]

在PUML 文件中有一個 global logic object 的描述宣告為:

<object name="userInfo" source="UserInfo.pgml"/>。

這個描述相對應的程式碼為:

public UserInfo lgObj_userInfo = new UserInfo();

b) logic object 的變數名要加上〝lgObj_〞這個前置敘述(prefix),用來 表示此變數代表的是一個logic object。即 lgObj_@objectName,這 裡的@objectName 指的是相對應的<object>的 attribute – name 的屬

性值。

c) 在 PUML 文件中描述的<board>所對應的 class,在轉換成 J2ME MIDP 程式碼之後,必須在此 BMngr_@user-interfaceName class 中,一開始就被宣告並產生物件出來(使用 new 這個關鍵字),但不 對外開放(使用 private 這個關鍵字)。由於<board>對應的 class,其 建構子(constructor)不需要參數,所以在產生物件的過程中,不需給 與初始值。

[例如]

在PUML 文件中有一個<board>的描述為:

<board name="welcomeBoard" title="Simple Demo">。

這個描述相對應的程式碼為:

private B_welcomeBoard welcomeBoard = new B_welcomeBoard();

d) 在 BMngr_@user-interfaceName class 中,要有下列變數宣告敘述:

public static BMngr_@user-interfaceName instance;

private Display display;

(@user-interfaceName 為<user-interface>的 attribute – name 的屬性值) e) 若在 PUML 文件中沒有特別說明的話,以第一個<board>所對應的

class,當第一個使用者介面呈現。在轉換成 J2ME MIDP 程式碼後,

display.setCurrent( )這個 method 來設定第一個要呈現的使用者介

面。

f) 實作 BMngr_Interface interface 的 changeBoard(String boardName ) method,實作方法如下:

比較傳入的參數值,然後利用

display.setCurrent( )這個 method 來切

換所要呈現的使用者介面。在轉換過程中,會將所有的<board>所對 應的使用者介面,都列入J2ME MIDP 的程式比較中,下面是 J2ME MIDP 程式碼的片段(圖 6-4):

public void changeBoard(String boardName){

if(boardName.compareTo("welcomeBoard") == 0){

display.setCurrent(welcomeBoard);

}

if(boardName.compareTo("infoBoard") == 0){

display.setCurrent(infoBoard);

}

if(boardName.compareTo("fruitBoard") == 0){

display.setCurrent(fruitBoard);

}

if(boardName.compareTo("colorsBoard") == 0){

display.setCurrent(colorsBoard);

} }

[圖 6-4 changeBoard( ) method 的 J2ME MIDP 範例程式碼片段]

g) 實 作 BMngr_Interface interface 的 getBoard(String boardName)

method,實作方法如下:

比較傳入的參數值,然後回傳參數值所指定的使用者介面的變數 (data type 為 displayable)。在轉換過程中,會將所有的<board>所對 應的使用者介面,都列入J2ME MIDP 的程式比較中,下面是 J2ME MIDP 程式碼的片段(圖 6-5):

public Displayable getBoard(String boardName){

Displayable displayable = null;

if(boardName.compareTo("welcomeBoard") == 0){

displayable = welcomeBoard;

}

if(boardName.compareTo("infoBoard") == 0){

displayable = infoBoard;

}

if(boardName.compareTo("fruitBoard") == 0){

displayable = fruitBoard;

}

if(boardName.compareTo("colorsBoard") == 0){

displayable = colorsBoard;

}

return displayable;

}

[圖 6-5 getBoard( ) method 的 J2ME MIDP 範例程式碼片段]

z 在 B_@boardName class 中:

a) 建構子(constructor)不需參數。

b) 在 PUML 文件中描述宣告的 local logic object 所對應的 class,在轉 換成J2ME MIDP 程式碼之後,必須在此 B_@boardName class 中,

一開始就被宣告並產生物件出來(使用 new 這個關鍵字),但不對外 開放(使用 private 這個關鍵字)。由於邏輯物件(logic object)對應的 class,其建構子(constructor)不需要參數,所以在產生物件的過程 中,不需給與初始值。

[例如]

在PUML 文件中有一個 local logic object 的描述宣告為:

<object name="fruitInfo" source="FruitInfo.pgml"/>。

這個描述相對應的程式碼為:

private FruitInfo lgObj_fruitInfo = new FruitInfo();

c) logic object 的變數名要加上〝lgObj_〞這個前置敘述(prefix),用來 表示此變數代表的是一個logic object。即 lgObj_@objectName,這 裡的@objectName 指的是相對應的<object>的 attribute – name 的屬 性值。

d) 在 PUML 文件中描述的使用者介面元件,在轉換成 J2ME MIDP 程 式碼之後,必須在此B_@boardName class 中,一開始就被宣告,

並且對外開放(使用 public 這個關鍵字)。

[例如]

在PUML 文件中有一個使用者介面的描述為:

<label name="helloMsg" showText="Hello, "/>。

這個描述相對應的程式碼為:

public StringItem helloMsg;

e) 在 PUML 文件中描述的<action> element,在轉換成 J2ME MIDP 程 式碼之後,必須在此B_@boardName class 中,一開始就被宣告並 產生物件出來(使用 new 這個關鍵字),但不對外開放(使用 private 這個關鍵字)。<action>對應於 Command 物件,且 command type 使 用Command.SCREEN,而 priority 設成 1。

[例如]

在PUML 文件中有一個使用者介面的描述為:

<action name="singleFruit" showText="Choose a Fruit">。

這個描述相對應的程式碼為:

private Command singleFruit =

new Command("Choose a Fruit", Command.SCREEN, 1);

f) 在建構子(constructor)中必須做的事有:

- 初始化使用者介面元件 - 設定 Command Listener

(Command Listener 即是本身 B_@boardName class,因為此 class 實作了 CommandListener interface)

- 把使用者介面元件,排放到包含它的使用者介面之中 - 在使用者介面中,加入用來驅動事件的 Command

[例如]

在PUML 文件中,使用者介面描述的片段為:

<board name="infoBoard" title="User Information">

<label name="helloMsg" showText="Hello, "/>

……

<action name="singleFruit" showText="Choose a Fruit">

……</action>

</board>

這個描述片段在建構子中,相對應的程式碼為:

public B_infoBoard( ) {

/* initialize UI component */

super("User Information");

helloMsg = new StringItem("Hello, ", "");

...

/* set up listeners */

this.setCommandListener(this);

/* append UI component */

this.append(helloMsg);

...

/* add commands */

this.addCommand(singleFruit);

...

}

z PUML 文件中的<textnote>,在轉換成 J2ME MIDP 程式碼時,對應到的 是TextField class。再產生相對應的 TextField 的物件時,預設可供使用 者輸入資料的欄位長度是50。

z 任何會使用到的圖檔,都要轉換成 png 格式(.png 檔)。

z 在轉換成 J2ME MIDP 程式碼時,要使用 PUML 文件裡,所描述的某個 使用者介面元件的狀態值時,記得要使用該使用者介面元件相對應的 class,裡頭的 method 來獲得,不要直接使用代表該使用者介面元件的 變數 (此為轉換時可能犯的錯誤)。

z 在 PUML 文件中,可能會透過<action> element content 的描述,來將

<listpaper>所代表的使用者介面元件的狀態值,交給 PUML 文件中所指 定的邏輯物件來處理。而處理的方式便是呼叫該邏輯物件相對應的class 中的method,使用者介面元件的狀態值便被當成參數,傳入該 method 之中。這個時候,必須分兩種狀況來做轉換的處理:

- 當<listpaper>的 attribute – mode 的屬性值為〝single〞時(單選) 使 用 <listpaper> 相 對 應 的 ChoiceGroup class 中 的 getSelectedIndex( ) method,來取得使用者介面元件的狀態值。

由於 PGML 文件所描述出來的邏輯物件,在處理<listpaper>所 對應到的使用者介面元件時,選單中選項的編號是從1 開始,

而在J2ME MIDP 中,選項編號是從 0 開使。所以利用所提到 的method 來取得狀態值之後,必須再加上 1,才能讓邏輯物件 來做邏輯運算的處理。

- 當<listpaper>的 attribute – mode 的屬性值為〝multi〞時(多選) 要將<listpaper>所對應的使用者介面元件的狀態值,轉化成一個

〝多選字串〞之後,才能交給邏輯物件來做邏輯運算的處理。

所謂〝多選字串〞,即是將使用者在選單中,所選擇的多個項目 的項目編號組合成一個字串,該字串稱為〝多選字串〞,例如:

使用者選擇了編號分別為 1、2、3、4 的項目,則該〝多選字串〞

便是〝1;2;3;4〞。

z 〝多選字串〞必須在做邏輯運算之前產生出來,產生多選字串的範例程 式碼如下(圖 6-6):

selectedStr = ""; //selectedStr是String

for(int i=0; i < iColors.size(); i++){ //iColors是ChoiceGroup if(iColors.isSelected(i)){

if(selectedStr != ""){

selectedStr = selectedStr + ";" + Integer.toString(i+1);

} else{

selectedStr = selectedStr + Integer.toString(i+1);

} }

}

[圖 6-6 多選字串的範例程式碼]

同樣地,由於 PGML 文件所描述出來的邏輯物件,在處理<listpaper>所 對應到的使用者介面元件時,選單中選項的編號是從1 開始,而在 J2ME MIDP 中,選項編號是從 0 開使。所以利用所提到的 method 來取得狀態 值之後,必須再加上1,才能讓邏輯物件來做邏輯運算的處理。

z 其他 J2ME MIDP 程式碼的轉換部份,則根據 J2ME MIDP 的語法,對 照著 PUML 的 element 做很直覺的轉換,可參考 appendix 中所附的 PUML 的原始碼,以及其轉換出來的 J2ME MIDP 程式碼。

B. PGML 轉成 J2ME MIDP 的轉換規則

接下來以條例式的方式,列出PGML 轉成 J2ME MIDP 的轉換規則。

z 一個 PGML 文件所描述的邏輯物件,在轉換成 J2ME MIDP 之後,會對 應到一個對外開放的class (使用 public 這個關鍵字),而該 class 的名稱 即為PGML 文件中<object>的 attribute – name 的屬性值。且這個 class 的建構子(constructor)不需任何參數。

z 這部份程式碼的轉換,並沒有特別的規則要遵守。則根據 J2ME MIDP 的語法,對照著PGML 的 element 做很直覺的轉換即可。可參考 appendix 中所附的PGML 的原始碼,以及其轉換出來的 J2ME MIDP 程式碼。