1 內容簡介
設計模式工具箱(Design Pattern Toolkit)是基於Eclipse的模板引擎,它向用戶提供一個模型驅動 的框架,幫助用戶簡化應用程序的開發。用戶通過模板定制應用程序的必要信息,設計模式工具箱幫助用 戶自動生成應用程序的所有構件。使用設計模式工具箱將顯著的加速常見應用程序的開發,與此同時,設 計模式工具箱向用戶提供了構建一類應用程序的最佳實踐,因此,使用它將幫助用戶分享最佳實踐的價值 。
本文首先介紹設計模式的基本概念,然後介紹設計模式工具箱(Design Pattern Toolkit)的框架,接 著,本文通過兩個例子分別介紹如何使用設計模式工具箱中已有的設計模式,以及如何編寫新的設計模式 。
2 設計模式
設計模式描述了軟件開發中經常出現的一類問題,以及這類問題的核心解決方案。使用此方案,用戶 將更加快捷而有效地開發解決此類問題的應用程序。設計模式通常由以下元素組成:
模式名稱:只有對不同的設計模式進行命名,設計人員才能在以後的交流中使用該名稱來簡潔地描述 一類問題以及其解決方案。
問題描述:問題的描述指出了什麼時候應用該設計模式是合適的,問題的描述不但包括問題本身也包 括了上下文的信息,甚至一些約束信息,只有當這些約束滿足時,應用該設計模式才被認為是有效的。
解決方案:它描述了解決一類問題必須涉及的各種元素,以及不同元素之間的關聯及協作。解決方案 並不是一個具體的實例,而是一個可以在不同場合多次利用的模板。
具體的說,開發某類應用程序(如,Portlet, Web Service, 或者 UML Profile)的專家對應用程序 的實現步驟進行編碼(Encoding),實現步驟可能包括獲取應用的需求以及生成應用程序的所有構件。編碼 的結果稱為模式(Pattern),其他開發人員只要使用此模式(事實上,它是專家的知識財產)就能夠輕松 的生成類似的應用程序。
圖1使用設計模式開發應用程序
圖1顯示如何使用設計模式開發應用程序,應用程序的開發人員通過XML文件提供應用程序關鍵信息的 描述,並選擇合適的模式,最後由引擎根據用戶提供的程序描述以及所應用的模式自動生成應用程序的所 有構件。
3 Design Pattern Toolkit框架
設計模式工具箱(Design Pattern Toolkit)中模式的結構是模型-視圖-控制器(Model-View- Controller),模式是專家的經驗總結,使用模式,能夠幫助用戶自動生成組成結構復雜的應用程序(如 ,數據庫bean,J2EE應用程序,Eclipse插件等)。下面分別介紹模型,視圖以及控制器:
模型(Model)是一個隱式的XML Schema,它描述了哪些特定信息對於應用程序是必須的 (如,Java Bean中所有屬性的名稱和類型,UML Profile中Stereotype的名稱及其包含的所有屬性)。針對每個具體 的應用,用戶需要編寫一個應用程序定義文件(appdef),而所有同類型的應用程序定義必須遵循唯一的 Schema。設計模式工具箱的一個優點是,它不會僵死的定義各種應用程序必須參照的Schema;相反,它賦 予了模式開發人員極大的自由,由他們決定構建應用程序必需的各種信息,以及各種信息將被如何獲取。
視圖(View)是一個模板的集合,模板由靜態文本和模板標簽組成,模板標簽指導如何從模型 (appdef)中抽取信息,以及如何將這些信息插入到靜態文本中。通過使用模板標簽,可以幫助用戶生成 不同種類的資源,標簽本身並沒有限制它們能夠被使用在什麼樣的模板中。一個模板可以被拆分成子模板 ,每個子模板負責生成應用程序的一部分,在實際執行中,不同的子模板被引擎有序的調用。例如,為源 代碼中的方法生成參數是最常見的模式之一,它應該被抽取出來作為獨立的子模板,從而能夠被其他模板 所調用。
控制器(Controller)也是一個模板,它由一系列的靜態文本和模板標簽組成,它的功能是控制視圖 模板何時以及如何被應用。控制模板對於輸出的內容進行精細的控制,甚至可以細致到輸出文本間的分隔 符。控制模板支持多個appdef的輸入,由模板標簽控制如何從不同的模型(appdef)中獲取信息,以及如 何對不同的信息進行組合。因此,用戶在設計模型時,能夠從不同的方面描述整個模型,並把每個方面定 義在一個appdef中,從而強化了模型層面的復用。例如,開發人員在設計模式時,把命名規范從模式的主 流程中剝離出來,用不同的appdef定義主流程和命名規范。
模式使用人員通過 appdef定義應用程序的模型,它通常是一個XML文件(也可以采用其他的格式,但 前提是用戶必須自己編寫解析器)。當使用人員選擇應用一個模式的時候,引擎獲取appdef以及該模式的 視圖模板和控制器模板,最後,生成一個端到端的應用程序,它可以包含各種Eclipse資源,同時跨越若 干個 Eclipse的項目。當引擎產生完所有的Eclipse資源後,building和validation 操作自動執行。自動 生成的Eclipse資源可能需要經過少量的修改,才能正確的運行。設計模式工具箱提供Round Tripping機 制,用戶只要在Eclipse資源中被修改過的地方作Round Tripping標記,再次運行轉換時,這些地方不會 被覆蓋。
4 利用已有的模式進行開發
本節以一個具體的應用開發為例,介紹如何利用Design Pattern Toolkit中已有的模式加速應用程序 的開發。
本節介紹的模式為UML Profile自動生成模式。使用UML Profile對UML的模型進行擴展已經是一個被廣 泛采用的標准做法,諸如RSA(Rational Software Architect)等基於Eclipse的集成開發工具,已經提 供了圖形的方式,幫助用戶訂制UML Profile。圖2顯示了UML Profile的基本組成元素:
.epx文件, UML Profile的定義通常保存在以.epx為後綴的文件裡。
Stereotype, UML Profile由若干Stereotype組成,每個Stereotype由若干屬性構成,其中以base$為 前綴的屬性,表明該Stereotype作用在什麼類型的UML元素上。
Association, 當用戶指定一個Stereotype作用於何種類型的UML元素上時,Association被自動建立並 添加到UML Profile中。
既然用戶能夠通過圖形界面,手工的建立UML Profile文件,使用Design Pattern Toolkit進行開發似 乎顯得有點笨拙,在下結論之前,請考慮這樣的場景,UML Profile被用來描述IBM的各種IT產品(數量的 巨大不言而喻),產品的開發人員可能並不了解如何使用建模工具去定制Profile,而且產品自身也在不 斷的升級和變更當中,因此,向產品開發人員提供一種直觀的方式開發和維護產品的Profile十分必要。 本節介紹如何使用設計模式工具箱中的UML Profile模式,幫助開發人員自動生成UML Profile。
圖2 UML Profile
4.1 創建新的插件工程
通過新建工程向導創建一個插件工程。從主菜單中選擇 New -> Project -> Design Pattern Toolkit, 然後選擇 Import Pattern into new Project 選項,因為我們不但要創建一個新的設計模式工 程,還要利用已有的模式進行開發。
點擊 Next,進入 New Template Set Project頁面,在Project Name條目中輸入項目名稱。
點擊 Next, 進入Import Pattern頁面,在此,用戶指定引用的模式,模式通常定義在以.patzip為後 綴的文件中,com.ibm.dptk_3.0.5.0\samples 目錄下保存了已經設計好的模式,選擇 TXMPatterns\umlProfile.patzip,點擊 Finish, 新的插件工程自動生成,且工程包含了umlProfile模式 。
圖3顯示了選擇創建新的Design Pattern Toolkit插件工程向導的界面。
圖3 新建Design Pattern Toolkit插件工程
4.2 修改視圖模板或控制模板
執行完4.1節所示的步驟,您將在Eclipse的 Workspace中看到新創建的插件工程。打開插件工程,您 將看到plugin和profile兩個文件夾,它們包含了umlProfile模式的視圖模板。
圖4 plugin.xml.pat文件
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
id="<attr node="plugin" name="id" />"
name="Plugin Plug-in"
version="1.0.0"
provider-name=""
class="<attr node="plugin" name="pluginJavaPkg" />.
<attr node="plugin" name="pluginJavaClass" />">
<runtime>
<library name="<attr node="plugin" name="jarName" />">
<export name="*"/>
</library>
</runtime>
<requires>
<import plugin="org.eclipse.ui"/>
<import plugin="org.eclipse.core.runtime"/>
<import plugin="com.ibm.xtools.uml2.msl"/>
<import plugin="com.ibm.xtools.emf.msl"/>
</requires>
<extension
point="com.ibm.xtools.emf.msl.Pathmaps">
<pathmap name="<attr node="plugin" name="shortName" format="u" />
_PROFILES" plugin="<attr node="plugin" name="id" />" path="profile"/>
</extension>
<extension
point="com.ibm.xtools.uml2.msl.UMLProfiles">
<iterate nodes="plugin/profile" name="profile">
<UMLProfile
required="false"
visible="true"
path="pathmap://<attr node="plugin" name="shortName" format="u" />
_PROFILES/<attr node="profile" name="profileEpxFile" />"
name="<attr node="profile" name="name" />"/>
</iterate>
</extension>
</plugin>
表1向您展示了umlProfile.patzip中包含的所有模板文件,您可以在已有模板基礎上做任意的修改, 以適合應用程序的需求。
我們通過一個簡單的模板文件(圖4),向您介紹如何通過模板標簽從模型中提取數據,並插入靜態文 本中。plugin.xml.pat文件定義了 plugin.xml的視圖模板,它由靜態文本以及模板標簽兩部分組成。 plugin.xml.pat由兩種類型的標簽組成:<attr> 和<iterate>標簽。
<attr>標簽被用來提取輸入的XML文件中節點屬性的值,通常包含node, name, 以及format屬性 :node屬性為一個xpath表達式,通過它,可以查找到appdef中的特定節點;name指定了node的一個屬性 名;format定義了如何對屬性值進行格式化。
<iterate>標簽被用來提取nodes中定義的所有節點,對於每個節點,把它與name的值關聯起來 ,這樣在循環體中,該節點能夠以name的值進行引用。
4.3 編寫模型文件appdef
模型文件appdef通常為XML格式,模式的設計人員定義一個隱式的XML Schema,該Schema描述了appdef 文件中應該包含哪些信息,以及這些信息如何被組織。針對UML Profile模式,我們編寫模型文件(圖5) :
圖5 sample.appdef文件
<app>
<plugin id="demo.gerken.profile.plugin" jarName="demo.jar" shortName="SUDemo" >
<profile name="SU_DEMO" >
<type name="Plugin" >
<association name="Prereqs" targetType="Plugin" />
<association name="Provides" targetType="Dialog" />
<attribute name="id" />
<attribute name="shortName" />
<attribute name="author" />
</type>
<type name="Dialog" >
<association name="Displays" targetType="Widget" />
<attribute name="title" />
<attribute name="width" />
<attribute name="height" />
</type>
<type name="Widget" >
<attribute name="type" />
<attribute name="name" />
<attribute name="scrollable" />
</type>
</profile>
</plugin>
</app>
4.4 應用UML Profile模式
選擇sample.appdef文件,點擊右鍵,選擇彈出菜單中的"Apply Pattern"條目,這時設計模式工具箱 搜索所有已經定義的模式,每個模式保存在一個.patzip文件中。您可以通過Window -> Preferences -> Patterns 修改模式文件的搜索路徑。
當您選擇"Apply Pattern"後,搜索路徑(包括其子目錄)下的所有模式將被列舉在一個彈出對話框中 ,如圖6所示。值得注意的是,當前工程中的模式也會被列舉出。選擇"UML Profile Pattern [profileDPTK]",點擊OK,模式將被應用。
當模式被成功的應用,您將看到圖7所示的對話框。這時,所有的Eclipse資源已經被生成。
圖6 選擇應用的Pattern
圖7 成功地應用Pattern
4.5 運行結果
當模式被成功的應用,在您的Workplace下會產生一個新的工程,名稱 為"demo.gerken.profile.plugin",當然,這取決與您在appdef文件中如何定義plugin的id。
圖8 包含UML Profile的工程
展開demo.gerken.profile.plugin工程,可以看到,該UML Profile插件工程包含了視圖模板中定義的 所有構件,它們分別是:
.project
.classpath
plugin.xml
build.properties
SUDemoPlugin.java
SU_DEMO.epx
至此,您應該體驗到使用設計模式工具箱開發應用程序的高效。如果用戶接受視圖模板和控制模板中 缺省的設置,他僅需要提供基於XML的appdef文件,然後點擊"Apply Pattern",應用程序就被自動的生成 。
5 開發新的模式
除了利用設計模式工具箱中現存的模式外,用戶還可以開發新的模式,新開發的模式應遵循模型-視圖 -控制器的架構。新開發的模式被打包為.patzip文件,並拷貝在模式文件目錄下,成為工具箱中新的模式 。
本節以一個簡單的例子向您展示如何編寫一個新的模式。編寫新的模式涉及以下幾步:首先定義隱式 的Model Schema,然後編寫視圖模板,最後編寫控制器模板。本節所展示的例子是編寫Java Bean模式, 您將發現,使用模板將有效的提高應用開發人員的效率。
5.1 定義隱式的Model Schema
Java Bean由一系列的屬性構成,每個屬性又被賦予了類型。雖然不同的Bean有不同的屬性或者不同類 型的屬性,但Java Bean的代碼中,無論是屬性的定義還是get,set操作都遵循著一定的規律。
隱式的Schema,指appdef文件所遵循的規范,不必使用實際的Schema進行定義,它僅作為模式開發人員 和模式使用人員之間共享的知識存在。下面我們來看一個具體的appdef的例子
圖9 Java Bean的appdef文件
<beans>
<bean class="Teacher">
<package>com/ibm/education</package>
<property name="name" type="String"/>
<property name="grade" type="int" />
<property name="room" type="String" />
</bean>
<bean class="Student">
<package>com/ibm/education</package>
<property name="name" type="String"/>
<property name="teacher" type="Teacher" />
</bean>
</beans>
從以上的模型,我們了解到,對與每個<bean>,必須指定它所在的包<package>,以及 Bean中各種屬性的定義。
5.2 定義視圖模板
視圖模板由靜態文本和模板標簽組成,模板標簽指導如何從模型(appdef)中抽取信息,並如何將這 些信息插入到靜態文本中。下面給出Java Bean模式的視圖模板,它保存在bean.pat中。
圖10 Java Bean的視圖模板bean.pat
package <content node="/bean/package" format="DP"/>;
public class <attr node="/bean" name="class"/> {
<iterate nodes="/bean/property" name="curProp" >
<attr node="curProp" name="type"/> <attr node="curProp" name="name"/>;
</iterate>
/* Constructor for <attr node="/bean" name="class"/> */
public <attr node="/bean" name="class"/>() {
super();
}
<iterate nodes="/bean/property" name="curProp" >
/**
* Gets the <attr node="curProp" name="name"/>
* @return Returns a <attr node="curProp" name="type"/>
*/
public <attr node="curProp" name="type"/>
get<attr node="curProp" name="name" format="U1"/> () {
return <attr node="curProp" name="name"/>;
}
/**
* Sets the <attr node="curProp" name="name"/>
* @param <attr node="curProp" name="name"/>
The <attr node="curProp" name="name"/> to set
*/
public void set<attr node="curProp" name="name" format="U1">
(<attr node="curProp" name="type"/> <attr node="curProp" name="name"/>) {
this.<attr node="curProp" name="name"/> = <attr
node="curProp" name="name"/>
}
</iterate>
}
針對以上視圖模板,有幾點需要解釋:
1.<content>標簽被用來從應用定義中抽取節點的內容。
2.<attr>標簽被用來獲取appdef中節點屬性的值,format="U1"意味著該字符串的首字母為大 寫。
3.<iterate>標簽定義了一個循環,對於每個節點,把它與name的值關聯起來,這樣在循環體 中,該節點能夠以name的值進行引用。
4.不同標簽之間可以存在多級牽套。
5.3 定義控制模板
控制模板提供了對視圖模板的管理和控制,圖11是Java Bean的控制模板control.pat文件。
圖11 Java Bean的控制模板control.pat
<iterate nodes="/beans/bean" name="curBean" >
<start
resource="%curBean/package%/%curBean(class)%.java"/>"
template="bean.pat" />
</iterate>
上述控制模板使用了<start>標簽,該標簽用來生成Eclipse的各種資源文件,resource定義了 資源文件保存的位置,template定義了視圖模板的位置。控制模板的執行結果是,針對appdef中的每個 bean,自動生成一個符合視圖模板bean.pat的 Java文件。
5.4 Export模式定義
選擇插件工程,點擊右鍵,從彈出菜單中選取 "Export Pattern to Zip File",指定合適的位置保存 模式的壓縮文件(.patzip)。該文件可以通過任何方式傳送給設計模式工具箱的使用人員,他們只要把 此文件拷貝在模式文件目錄下,即添加到工具箱中。
6 總結
設計模式工具箱(Design Pattern Toolkit)向用戶提供了一個模型驅動的框架,簡化了應用程序的 開發。使用設計模式工具箱將顯著的加速應用程序的開發,與此同時,設計模式工具箱向用戶提供了構建 一類應用程序的最佳實踐,因此,使用它將幫助用戶分享最佳實踐的價值。