使用 Design Pattern Toolkit 進行模型驅動的開發入門
當大多數人想到模型驅動的開發時,首先出現在腦海中的是使用某種 UML 模型進行編碼以及從該模型生成相應的構件。然而,事情並不總是這樣的。模型存在於各種各樣的地方。模型是任何驅動產生過程或行為的構件。
模型驅動的開發具有許多目標:
- 減少在開發常見的構件上耗費的時間。
- 維護最小限度的資訊量。
- 以一種中立的方式對模型進行維護,這使得從相同的模型生成多種型別的實現和構件成為可能。例如,我們應該可以使用不同的模板從相同的模型中生成 Web UI 和本地的 GUI UI。
本文將通過設計模式工具箱來介紹模型驅動的開發,該工具箱是一種支援 Eclipse 的模板引擎,用來根據可自定義的、模型驅動體系結構轉換(JET2 的一種推動技術,請參見
有關更多的內容或下載設計模式工具箱,請訪問 IBM alphaWorks。
DPTK 中的模式創造者使用標記來構建模式模板。這些標記具有特殊的行為,用來訪問模型、執行邏輯並完成各種各樣其他的任務。豐富的標記提供了大量的功能,並且實 際上代表了構建任何複雜的 MDD 轉換所需的基本構件。模式模板的主要目標是生成相應的構件,然而正如我們將在下一部分中看到的,模式模板可以用來完成更多的任務。
為了能夠更好地理解相關內容,讓我們先來研究下面簡單的模式模板:
圖 1. 簡單的模式模板
這是一個非常簡單的 DPTK 檢視:
- 該模式應用於簡單的 XML 模型。
- DPTK 引擎呼叫了一個模式模板。模式模板使用 DPTK 標記語言替換其中動態的部分。
- 並生成最終的構件。
從簡單的 XML 宣告生成相應的 Java™ 類並不是什麼讓人激動的事情,但是其目的是為對整個流程進行研究奠定基礎。接下來,我們將對其進行更仔細的研究。
模型-檢視-控制器 (MVC) 是一種常用的設計模式,用於構建許多不同型別的應用程式。例如,在 Java EE 中,諸如 JavaServer™ Faces 和 Struts 這樣的框架都專門提供了 MVC 設計。MVC 允許應用程式中事務的分離,其中模型代表資料和業務邏輯,檢視代表如何觀察資料,而控制器則處理使用者的輸入、模型呼叫和檢視選擇。
事實上,MVC 是使用設計模式工具箱構建 MDD 解決方案的一種優秀的設計模式。考慮一下圖 2:
圖 2. MVC 作為一種設計模式
DPTK 標記庫包含各種各樣的標記,它們可以用來完成許多工。因此,我們可以使用特定的角色構建經過精心設計的模板。例如,控制器模式模板將生成許多構件的整體容器,並呼叫各種其他的模板,而這些模板將生成特定的構件。
通過下面一系列練習,您將可以通過示例瞭解並掌握如何使用 MVC 設計模式生成相應的構件。您可以在結尾處訪問DPTK 並下載本文中的示例資料。
在進行模型驅動的開發的過程中,最好時刻將目標銘記於心。也就是說,手動地構建出第一個案例。這樣,您就可以弄清楚究竟需要生成什麼樣的內容。在開 始這項工作前,我們將向您介紹一個示例樣本(在後續的文章中,我們將討論一些工具,這些工具可以用來對樣本進行分析,以便生成模式本身)。在這個示例中, 我們提供了在 IBM Rational® Software Architect 中使用設計模式工具箱的相關說明。然而,也可以使用安裝了 DPTK 外掛的普通的 Eclipse 輕鬆地完成這個練習(請參見參考資料部分)。
-
啟動 Rational Software Architect,並開啟一個新的、空的工作區:
-
通過選擇 Window => Open Perspective => Other(圖 3),切換到設計模式工具箱透檢視。
圖 3. Open perspective -
從對話方塊(圖 4)中選擇 Design Pattern Toolkit。
圖 4. Select perspective
-
-
匯入我們的示例 Java 樣本,這是我們將要生成的 JavaBean 的示例:
-
檢查其中的構件:
-
展開該專案(圖 8)並開啟檔案 sample.appdef。
圖 8. 開啟示例這個檔案將包含大量的 XML 標記。對於那些熟悉 IBatis(請參見參考資料部分)的讀者,您將注意到,這個 XML 模型(清單 1)反映了 iBatis 對映檔案的 parameterMap 結構。它定義了 Java 類,以及每個屬性的相關屬性和資料型別,並且將作為生成過程的模型。
(請記住,這裡的目標是熟悉如何編寫模式模板。這裡並沒有給出維護模型的最佳實踐。在實際情況下,輸入和內部模型並不匹配。事實上,稍後我們將對內部模型進行修改。)
清單 1
<app>
<parameterMap class="com.ibm.dptk.ibatis.dataobject.Customer"
id="newCustomerMap" >
<parameter property="customerId" javaType="java.lang.Integer"/>
<parameter property="name" javaType="java.lang.String"/>
<parameter property="address1" javaType="java.lang.String" />
<parameter property="address2" javaType="java.lang.String" />
<parameter property="city" javaType="java.lang.String" />
<parameter property="state" javaType="java.lang.String" />
<parameter property="zip" javaType="java.lang.String" />
</parameterMap>
</app> -
如果開啟 Java 類,您將發現一個簡單的 JavaBean,它具有一些簡單的屬性以及相應的 setter 和 getter。在這個練習中,為了方便起見,我們根據 JavaBean 屬性以及相應的 getter 和 setter 對其進行分組。這個 JavaBean 如下所示。
清單 2public class Customer implements Serializable {
private java.lang.String address1;
/**
* Gets the address1
*
* @return Returns a java.lang.String
*/
public java.lang.String getAddress1() {
return address1;
}
/**
* Sets the address1
*
* @param java.lang.String
* The address1 to set
*/
public void setAddress1(java.lang.String address1) {
this.address1 = address1;
}
...
-
上面是一種非常簡單的檢查目標示例的方法。在許多情況下,模型和生成的構件並不是那麼明顯。我們將在後續的文章中演示更高階的分析技術,以便對樣本進行分析並發現其中的模型。
為了使您清楚地瞭解如何建立和測試模式,現在我們將建立一個模式專案,並將這個模式應用於一個模型。
-
建立模式專案。
-
右鍵單擊 Navigator 檢視並選擇 New => New pattern project。(圖 9)
圖 9. 建立新的模式 -
將該模式命名為
IBatisJavaBeanGenerator
,然後按 Next(圖 10)。
圖 10. 建立新的模式 -
對下列欄位進行驗證或輸入相應的值:
- Pattern Name:輸入模式名稱。
- Pattern ID:唯一模式 ID 值。
- Appdef Type:儲存您的模型的副檔名型別。當針對一個模型執行具有這種副檔名的模式時,這個模式將顯示可適用於這個模型的模式的列表。
- Applies To:表示該模型是否在單個檔案中,即是否使用單個檔案進行程式碼生成。
圖 11. 建立新的模式
-
-
DPTK 設計為使用模型-檢視-控制器模式。因此,設計模式工具箱專案嚮導建立了一個模型-檢視-控制器的預設專案結構。(圖 12)
圖 12. MVC 專案結構-
控制器資料夾下的模板將會用來實現生成過程。當您將模式應用於模型時,首先會呼叫 control.pat 檔案。
-
在檢視資料夾中,模式作者將儲存用來表示資料檢視的模板。
-
這個專案還建立了一個虛擬的 sample.appdef 檔案(圖 13)。在 Navigator 檢視中選擇該檔案以開啟它。
圖 13. 虛擬的 sample.appdef 檔案 -
圖 14 中顯示的是一個僅具有簡單的 <app> 標記的 sample.appdef 檔案。
圖 14. 虛擬的 sample.appdef 檔案 -
DPTK 還提供了簡單的檢視模板的示例,即 dump.pat 檔案(圖 15)。
圖 15. 檢視模板示例 -
如果開啟這個 dump.pat 檔案,您將發現另一個簡單的檔案,如清單 3 所示。這個檔案採用了記憶體 (In-memory) 模型,並將其中的內容轉儲到一個檔案中。
清單 3<exists node="/*/.." attr=".encoding">
<?xml version="1.0" encoding="<attr node="/*/.." name=".encoding"/>"?>
</exists>
<exists node="/*/.." attr=".name">
<!DOCTYPE <attr node="/*/.." name=".name"/> PUBLIC "<attr node="/*/.."
name=".publicId"/>" "<attr node="/*/.." name=".systemId"/>">
</exists>
<dump node="/*" format="true" entities="true"/> -
清單 4 顯示了 control.pat 檔案中的內容。如果檢視程式碼中的粗體部分,您將看到我們使用 <start> 模板標記來呼叫 dump.pat。這個 start 標記將呼叫模式模板,並將結果轉儲到指定的資源,在我們的示例中,是 dump.xml 檔案。
清單 4*** High-Level Controller
*** Apply naming conventions
<include template="ibatis.java.bean.generator/controller/naming.pat"/>
*** Derive names and other data
<include template="ibatis.java.bean.generator/controller/derived.pat"/>
*** Dump the modified appdef file for testing and debug purposes
<start template="ibatis.java.bean.generator/view/dump.pat" resource="dump.xml"
replace="true"/>
-
-
現在我們可以來研究如何呼叫這些模式。
-
右鍵單擊所包含的 sample.appdef 檔案,然後選擇 Apply Pattern。(圖 17)
圖 17. 應用模式 -
選擇 Ibatis Java Bean Generator 並按 OK。(圖 18)
圖 18. 生成模式 -
在生成該模式後,您應該看到圖 19 中所示的文字框。
圖 19. 成功地應用模式 -
您應該還有一個名為 dump.xml 的檔案(圖 20)。
圖 20. Dump.xml 檔案 - 如果仔細檢查 dump.xml (圖 21)的內容,您將發現,它是一個複製了該模型的簡單的 XML 檔案。(當然這並不是什麼非常令人激動的事情,但是對於除錯來說卻非常有用。)
圖 21. Dump.xml 檔案 -
如果您感興趣,可以將 sample.appdef 從樣本專案中複製到模式專案,並覆蓋預設的專案。
-
重新將該模式應用於 sample.appdef(圖 22)。
圖 22. 重新應用模式 -
現在,dump.xml 檔案應該包含了我們的樣本模型。(圖 23)
圖 23. Dump.xml 檔案
-
|
現在可以建立我們的第一個模板了。我們的目標是從 sample.appdef 檔案生成一個 JavaBean。
-
要生成 Java 原始檔,生成過程必須發生在一個 Java 專案中。設計模式工具箱可以生成各種各樣的 Eclipse 專案型別,但是考慮到我們的目的,我們將手動地建立一個 Java 專案:
-
在設計模式工具箱中選擇 File => New=> Project(圖 24)。
圖 24. 建立 Java 專案 -
選擇 Java Project(圖 25)。
圖 25. 建立 Java 專案 -
將該專案命名為
MyJavaBeanProject
,並按 Finish(圖 26)。
圖 26. 建立 Java 專案 -
當詢問是否切換到 Java 透檢視時,回答 No(圖 27)。
圖 27. 拒絕透檢視切換 -
將 sample.appdef 檔案從樣本中複製到這個 Java 專案(圖 28)。
圖 28. 複製 sample.appdef 檔案
-
-
現在我們將建立一個模式模板。右鍵單擊 view 資料夾,選擇 New => File(圖 29),並將新的檔案命名為
JavaBean.pat
(圖 30)。
圖 29. 建立模式模板
圖 30. 建立模式模板 -
使用 Customer JavaBean 作為起點,將 JavaBean 程式碼複製到該模板中。從樣本專案中複製 Customer.java 程式碼,並將其貼上到該模板中。這個 pat 檔案應該與圖 31 中所示的檔案類似。
圖 31. 建立模式模板 -
要使 JavaBean 模板成為我們的模式中的一部分,必須將其新增到 control.pat。
-
新增另一個 start 標記,如清單 5 中的粗體文字所示(或從下載檔案的 C:/DPTKArticles/Part1/CodeSnippet1.txt 中進行復制)。template 屬性指向 JavaBean.pat 檔案。resource 屬性定義了檔案的名稱。(資原始檔夾是相對於 Eclipse 專案中指定的 src 目錄,而不是專案的根目錄,因為檔案型別為 java。)
清單 5<start template="ibatis.java.bean.generator/view/dump.pat" resource="dump.xml"
project="MyJavaBeanProject" replace="true"/>
<start template="ibatis.java.bean.generator/view/JavaBean.pat"
resource="com/ibm/dptk/ibatis/dataobject/Customer.java" replace="true"/> -
通過右鍵單擊 MyJavaBeanProject 中的 sample.appdef,應用這個模式(圖 33)。
圖 33. 應用模式 -
從模式列表中選擇 Ibatis Java Bean Generator(圖 34),這時應該生成了 Customer 類(圖 35)。
圖 34. 應用模式
圖 35. 生成的 Customer 類
-
現在,我們將使用一些設計模式工具箱標記來構建 JavaBean 模式模板。
-
設計模式工具箱中包含一些標記,這些標記允許我們訪問模型並使用模式中的資料。第一個標記是訪問模型中的屬性資料:
-
第一個標記是 <attr> 標記,它允許我們訪問特定標記中的屬性。<attr> 標記還有其他的一些屬性,它們允許您以某種方式對文字進行格式化。如圖 38 所示,使用清單 6 中的文字替換包名和類名。您還可以從 C:/DPTKArticles/Part1/CodeSnippet2.txt 中複製相應的文字。(另外,下載檔案中提供了一個完整的模板,如果您希望載入它。)
圖 38. 替換包名和類名
清單 6package <attr node="/app/parameterMap" name="class" format="QP" />;
import java.io.Serializable;
public class <attr node="/app/parameterMap " name="class" format="QC">
implements Serializable {
-
-
您可以使用標記對模型中的屬性資料進行轉儲。然而,有時可能需要修改記憶體模型。開啟 control.pat 檔案(圖 39)並檢查我們以前新增的 start 模板標記(清單 7)。
圖 39. 開啟 control.pat 檔案
清單 7<start template="ibatis.java.bean.generator/view/JavaBean.pat"
resource="com/ibm/dptk/ibatis/dataobject/Customer.java"
replace="true"/> -
問題是,我們不能在另一個 DPTK 標記中使用 attr 標記。DPTK 提供了一種可用來訪問資料的動態表示式語言。有一個問題是,類的格式需要在一個目錄結構中。動態表示式可能會變得很笨拙。解決這個問題的另一種方法是,對 記憶體模型進行修改。這種方法允許您以不同的方式對相同的資料進行格式化,然後直接訪問它。<setAttr> 標記允許您設定現有標記的屬性。
-
新增清單 8 的粗體文字中的標記(或從 C:/DPTKArticles/Part1/CodeSnippet3.txt 中進行復制)。這裡,我們以幾種不同的方式對類名進行格式化。
清單 8<setAttr node="/app/parameterMap" name="classname" ><attr node="/app/parameterMap"
name="class"></setAttr>
<setAttr node="/app/parameterMap" name="name" ><attr node="/app/parameterMap"
name="class" format="QC"></setAttr>
<setAttr node="/app/parameterMap" name="dir"><attr node="/app/parameterMap" name="class"
format="PD"></setAttr>
<setAttr node="/app/parameterMap" name="package"><attr node="/app/parameterMap"
name="class" format="QP" /></setAttr>
*** Dump the modified appdef file for testing and debug purposes
<start template="ibatis.java.bean.generator/view/dump.pat" resource="dump.xml"
project="MyJavaBeanProject" replace="true"/>
<start template="ibatis.java.bean.generator/view/JavaBean.pat"
resource="com/ibm/dptk/ibatis/dataobject/Customer.java" replace="true"/> -
應用該模式,然後檢視 dump.xml 檔案,它顯示了記憶體模型的情況(圖 40)。我們並沒有修改原始的輸入模型。
圖 40. 記憶體模型
-
-
現在,我們可以對模板進行修改,以訪問新的模型元素:
-
修改 resource 屬性的值,如下面的粗體文字所示。
清單 9<start template="ibatis.java.bean.generator/view/JavaBean.pat"
resource="%/app/parameterMap(dir)%
.java" replace="true"/> -
如下所示,回到 JavaBean.pat 並修改 attr 標記,以引用模型中新的資料。
清單 10package <attr node="/app/parameterMap" name="package" />;
import java.io.Serializable;
public class <attr node="/app/parameterMap" name="name"> implements
Serializable {
-
-
接 下來,我們需要生成 JavaBean 屬性。因為 Java 屬性的數目是可變的,所以我們需要對模型進行遍歷。設計模式工具箱中具有 iterate 標記。(另外,從 C:/DPTKArticles/Part1/CodeSnippet4.txt 中為這部分內容複製完整的類程式碼段。)
-
開啟 the JavaBean.pat 檔案。
-
我們僅需要一個 Java 屬性作為模型。刪除第一個屬性以外所有的屬性。保留 address 屬性以及它的 getter 和 setter。
-
在清單 11 中新增 iterate 標記,使之包含 Java 屬性、getter 和 setter。圖 41 演示了這個示例。
清單 11<iterate nodes="/app/parameterMap/parameter" name="currentParameter" >
圖 41. Iterate 標記 -
使用下面的標記替換類和屬性。可以參考圖 42,以瞭解在何處進行替換。
清單 12private <attr node="currentParameter" name="javaType"/> <attr
node="currentParameter" name="name"/>;
圖 42. 替換型別和屬性 -
最後,如清單 13 中的粗體文字所示,對 setter 和 getter 標記進行更新,並應用該模式(圖 43)。
清單 13package <attr node="/app/parameterMap" name="package" />;
import java.io.Serializable;
public class <attr node="/app/parameterMap" name="name"> implements
Serializable {
<iterate nodes="/app/parameterMap/parameter"
name="currentParameter" >
private <attr node="currentParameter" name="javaType"/> <attr
node="currentParameter" name="name"/>;
/**
* Gets the <attr node="currentParameter" name="name"/>
* @return Returns a <attr node="currentParameter"
name="javaType"/>
*/
public <attr node="currentParameter" name="javaType"/>
get<attr
node="currentParameter" name="name" format="U1"/> />() {
return <attr node="currentParameter" name="name"/>;
}
/**
* Sets the <attr node="currentParameter" name="name"/>
* @param <attr node="currentParameter" name="javaType"/> The
<attr node="currentParameter" name="name"/> to set
*/
public void set<attr node="currentParameter" name="name"
format="U1"/> /> (<attr node="currentParameter" name="javaType"/>
<attr node="currentParameter" name="name"/>) {
this.<attr node="currentParameter" name="name"/>
= <attr
node="currentParameter" name="name"/>;
}
</iterate>
}
圖 43. 應用模式
-
要了解我們的模式的通用性,那麼需要通過生成其他的一些內容來對其進行測試。我們的模式剛剛從單個模型生成了單個檔案。然而,我們可以進行一些細微 的修改。(另外,您可以從 C:/DPTKArticles/Part1/Part1Solution.zip 載入解決方案專案交換檔案,並執行最後的結果。)
-
讓我們向模型中新增另一個 JavaBean。從 MyJavaBeanProject 中開啟 sample.appdef 檔案(圖 44),然後新增一個附加的 parameterMap 標記,如清單 14 中的粗體文字所示。
圖 44. 開啟 sample.appdef 檔案
清單 14<app>
<parameterMap class="com.ibm.dptk.ibatis.dataobject.Customer"
id="newCustomerMap" >
<parameter property="customerId" javaType="java.lang.Integer"/>
<parameter property="name" javaType="java.lang.String"/>
<parameter property="address1" javaType="java.lang.String" />
<parameter property="address2" javaType="java.lang.String" />
<parameter property="city" javaType="java.lang.String" />
<parameter property="state" javaType="java.lang.String" />
<parameter property="zip" javaType="java.lang.String" />
</parameterMap>
<parameterMap class="com.ibm.dptk.ibatis.dataobject.Order"
id="newCustomerMap" >
<parameter property="customerId" javaType="java.lang.Integer"/>
<parameter property="orderId" javaType="java.lang.String" />
</parameterMap>
</app> -
接下來,要對該模式進行更新,以使它能夠生成多個檔案,我們需要對 control.pat 檔案進行更新:
-
開啟 the control.pat 檔案,並按照下面粗體文字的內容進行修改。我們可以使用 iterate 標記批量地生成檔案,以及批量地更新模型。
清單 15*** High-Level Controller
*** Apply naming conventions
<include template="ibatis.java.bean.generator/controller/naming.pat"/>
*** Derive names and other data
<include template="ibatis.java.bean.generator/controller/derived.pat"/>
<iterate nodes="/app/parameterMap" name="currentBean" >
<setAttr node="currentBean"
name="classname" ><attr
node="currentBean"
name="class"></setAttr>
<setAttr node="currentBean"
name="name" ><attr
node="currentBean" name="class"
format="QC"></setAttr>
<setAttr node="currentBean"
name="dir"><attr
node="currentBean" name="class"
format="PD"></setAttr>
<setAttr node="currentBean"
name="package"><attr
node="currentBean" name="class"
format="QP" /></setAttr>
</iterate>
*** Dump the modified appdef file for testing and debug purposes
<start template="ibatis.java.bean.generator/view/dump.pat" resource="dump.xml"
project="MyJavaBeanProject" replace="true"/>
<iterate nodes="/app/parameterMap" name="currentBean" >
<start template="ibatis.java.bean.generator/view/JavaBean.pat"
resource="%currentBean(dir)%.java" replace="true"/>
</iterate>
package <attr node="currentBean" name="package" />;
import java.io.Serializable;
public class <attr node="currentBean" name="name"> implements Serializable {
<iterate nodes="currentBean/parameter" name="currentParameter" >
private <attr node="currentParameter" name="javaType"/> <attr
node="currentParameter" name="property"/>;
/**
* Gets the <attr node="currentParameter" name="property"/>
* @return Returns a <attr node="currentParameter" name="javaType"/>
*/
public <attr node="currentParameter" name="javaType"/> get<attr
node="currentParameter" name="property" format="U1"/> />() {
return <attr node="currentParameter" name="property"/>;
}
/**
* Sets the <attr node="currentParameter" name="property"/>
* @param <attr node="currentParameter" name="javaType"/> The <attr
node="currentParameter" name="property"/> to set
*/
public void set<attr node="currentParameter" name="property"
format="U1"/> />
(<attr node="currentParameter" name="javaType"/> <
attr node="currentParameter" name="property"/>) {
this.<attr node="currentParameter" name="property"/>
= <attr node="currentParameter" name="property"/>;
}
</iterate>
}
-
在 本文中,我們通過一個簡單的示例向您介紹瞭如何使用 DPTK。然而,DPTK 還可以用來以最少的工作量解決非常複雜的問題。我們重點關注於構建模式模板;DPTK 還提供了相應的分析工具,用於從現有的實現中發現模型。這使得我們可以通過反向工程將程式碼轉換到相應的中性模型和功能,它們可以作為構建基於資產的業務的 基礎。在後續文章中,將介紹一些更復雜的問題,以及如何使用設計模式工具箱中更高階的特性來解決這些問題。
本文作者要感謝 Geoffrey Hambrick 為本文提供了有價值的建議和評論。
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
Code samples | DPTKArticleMaterials.zip | 11 KB | FTP|HTTP |
Roland Barcia 是位於紐約/新澤西地區的 IBM WebSphere 軟體服務部的一位認證 IT 專家。他是 IBM WebSphere: Deployment and Advanced Configuration 的合著者。有關 Roland 的詳細資訊,請訪問他的網站。 |
Chris Gerken 是 IBM Software Services for WebSphere group 中 Asset Reuse Enablement Team 的成員。他建立和編寫了設計模式工具箱。 |