UML軟件開發(fā)與建模工具Enterprise Architect教程:創(chuàng)建項目特定的代碼生成器(上)
Enterprise Architect是一個對于軟件系統(tǒng)開發(fā)有著極好支持的CASE軟件(Computer Aided Software Engineering)。EA不同于普通的UML畫圖工具(如VISIO),它將支撐系統(tǒng)開發(fā)的全過程。在需求分析階段,系統(tǒng)分析與設計階段,系統(tǒng)開發(fā) 及部署等方面有著強大的支持,同時加上對10種編程語言的正反向工程,項目管理,文檔生成,數(shù)據(jù)建模等方面。可以讓系統(tǒng)開發(fā)中各個角色都獲得最好的開發(fā)效率。
您是否曾經(jīng)想過從Enterprise Architect UML或SysML模型生成代碼?您是否嘗試過自定義Enterprise Architect的代碼模板框架?不要放棄特定于項目的代碼生成器的夢想,而要閱讀它們實現(xiàn)起來的難易程度。
需要代碼生成器
與實現(xiàn)相比,好的軟件或系統(tǒng)架構(gòu)具有更高的抽象級別。它應該是一個一致的模型,用于記錄決策并忽略不必要的(通常是技術(shù)上的)細節(jié)??紤]一下圖1中的類圖。它顯示了一個域模型,該模型定義了商店允許客戶訂購商品所需的數(shù)據(jù)結(jié)構(gòu)。每個類的屬性都進行了詳細建模,但是省略了其他不必要的方面,例如訪問屬性的操作。
圖1:示例UML模型
如果在開始實施之前先對軟件體系結(jié)構(gòu)/設計進行了準備,那么代碼生成可以避免很多繁瑣且容易出錯的工作。商業(yè)開箱即用的代碼生成器通常不會更改抽象程度。這就是為什么它們通常不符合項目需求的原因。
可以根據(jù)項目特定需求定制Enterprise Architect的代碼模板框架。但這需要一些初步培訓。通常,如基于Eclipse的Enterprise Architect Models的代碼生成中所述,很難達到預期的結(jié)果。
一個簡單的項目專用代碼生成器
我更喜歡使用Java或Xtend之類的通用編程語言來實現(xiàn)代碼生成器。由于Xtend具有模板表達,因此特別適合于實現(xiàn)模板。它們允許將可執(zhí)行代碼嵌入要生成的文本中。感覺就像在編程PHP,JSP或JSX。在代碼清單1只顯示了寫的Xtend代碼生成模板。它為圖1的類圖中聲明的類生成Java類。
package com.yakindu.ea.examples.orderingsoftware.template import com.yakindu.bridges.ea.examples.runtime.codegen.EACodegen import org.eclipse.uml2.uml.Class import org.eclipse.uml2.uml.NamedElement class ClassTemplate { @EACodegen("Java") def String generate(Class element) ''' package ?element.package.javaQualifiedName?; ?val superType = element.generals.findFirst[true]?.name? ?val extends = '''?IF !superType.isNullOrEmpty? extends ?superType??ENDIF?'''? public?IF element.isAbstract? abstract?ENDIF? class ?element.name??extends? { ?FOR attribute : element.ownedAttributes SEPARATOR System.lineSeparator? ?val type = attribute.type?.javaQualifiedName? ?IF 1 != attribute.upper? ?val defaultValue = '''new java.util.LinkedList<?type?>()'''? private final java.util.List<?type?> ?attribute.name? = ?defaultValue?; ?ELSE? private ?type? ?attribute.name?; ?ENDIF? ?ENDFOR? ?FOR attribute : element.ownedAttributes SEPARATOR System.lineSeparator? ?val type = attribute.type?.javaQualifiedName? ?IF 1 != attribute.upper? public List<?type?> get?attribute.name.toFirstUpper?() { return ?attribute.name?; } ?ELSE? public ?type? get?attribute.name.toFirstUpper?() { return ?attribute.name?; } ?ENDIF? ?IF 1 == attribute.upper? ?val params = '''?type? ?attribute.name?'''? public void set?attribute.name.toFirstUpper?(?params?) { this.?attribute.name? = ?attribute.name?; } ?ENDIF? ?ENDFOR? } ''' protected def String getJavaQualifiedName(NamedElement element) { element.qualifiedName.replace("::", ".") } }
清單1:用Xtend編寫的示例代碼生成模板
在顯示生成的Java代碼清單2, 3 和 4看起來并不像手寫的,因為合格的名稱來代替進口。稍后將在圖4中通過方法collectImports和進行改進printImports。
package com.example.orderingsoftware; public abstract class AbstractIDObject { private java.util.UUID id; public java.util.UUID getId() { return id; } public void setId(java.util.UUID id) { this.id = id; } }
清單2:清單1中的代碼生成模板生成的類AbstractIDObject的Java代碼
package com.example.orderingsoftware; public class OrderItem extends AbstractIDObject { private java.math.BigInteger amount; private com.example.orderingsoftware.Article article; public java.math.BigInteger getAmount() { return amount; } public void setAmount(java.math.BigInteger amount) { this.amount = amount; } public com.example.orderingsoftware.Article getArticle() { return article; } public void setArticle(com.example.orderingsoftware.Article article) { this.article = article; } }
package com.example.orderingsoftware; public class Order extends AbstractIDObject { private java.util.Date date; private com.example.orderingsoftware.Customer customer; private final java.util.List<OrderItem> items = new java.util.LinkedList<OrderItem>(); public java.util.Date getDate() { return date; } public void setDate(java.util.Date date) { this.date = date; } public com.example.orderingsoftware.Customer getCustomer() { return customer; } public void setCustomer(com.example.orderingsoftware.Customer customer) { this.customer = customer; } public java.util.List<com.example.orderingsoftware.OrderItem> getItems() { return items; } }
清單4:由清單1中的代碼生成模板生成的Order類的Java代碼
如果仔細查看清單1中的模板,您將意識到它對Enterprise Architect一無所知。取而代之的是,它處理UML元模型的實例,這要歸功于Eclipse UML 2項目,它在Eclipse中可用。YAKINDU EA-Bridge是Enterprise Architect和UML之間缺少的連接。它是一個API,可提供對Enterprise Architect UML和SysML模型的符合UML的讀寫權(quán)限。Enterprise Architect項目背后的數(shù)據(jù)庫會自動轉(zhuǎn)換為UML元模型的實例。作為開發(fā)人員,這具有三大優(yōu)勢:
- 您的代碼與基于UML 2項目的其他工具(如Papyrus)兼容。
- 對Enterprise Architect模型的高性能讀寫訪問,而無需對Enterprise Architect的數(shù)據(jù)庫架構(gòu)進行反向工程。
- 您無需了解有關(guān)YAKINDU EA-Bridge API的任何知識。作為開發(fā)人員,它完全是隱藏的,因為YAKINDU EA-Bridge會將自身集成到Eclipse Modeling Framework(EMF)的生態(tài)系統(tǒng)中。
YAKINDU EA-Bridge帶有可選的Eclipse IDE集成,該集成允許一個人實現(xiàn)特定于項目的代碼生成器。這些代碼生成器通常是原型開發(fā)的,并且僅在特定上下文中執(zhí)行。因此,至關(guān)重要的是,與手動編碼相比,減少開發(fā)工作量。要實現(xiàn)特定于項目的代碼生成器,您要做的就是將EAP文件放置在Eclipse項目中,并使用注釋代碼生成模板中的方法@EACodegen。帶注釋的方法應接受應為其生成代碼的UML元素作為唯一參數(shù),并返回生成的文本。如果您的Enterprise Architect模型由遠程數(shù)據(jù)庫(例如Microsoft SQL Server)托管,則可以使用快捷方式文件 而不是EAP文件。
例如,通過主菜單項“ Project,Clean ...”自動或手動構(gòu)建項目時,將為所有EAP文件中聲明的所有UML類啟動模板。當然,僅考慮模板項目中存儲的EAP文件。生成的代碼保存在類的限定名稱指定的文件中。文件擴展名由@EACodegen注釋的參數(shù)指定。Eclipse項目的結(jié)構(gòu)如圖2所示。
圖2:Eclipse中的示例項目結(jié)構(gòu)
請注意,YAKINDU EA-Bridge是一個API。它允許您以任何方式處理Enterprise Architect模型。實際上,最初的用例是全面的代碼生成器,例如基于UML架構(gòu)的Autosar RTE生成器。
=====================================================
想要了解或購買Enterprise Architect正版版權(quán),請咨詢慧都官方客服
關(guān)注下方微信公眾號,及時獲取產(chǎn)品最新消息和最新資訊