代码自动生成器

2024-05-26

代码自动生成器(精选7篇)

代码自动生成器 篇1

摘要:代码自动生成作为一种程序自动化技术,可有效解决现代大规模软件开发过程中遇到的重复编写代码问题,提高了软件开发的效率和质量。文中介绍了一种基于XML的代码生成技术,并以XML转换技术为基础,给出了XML的代码生成工具的结构设计,及其实现框架和关键步骤。以该工具在雷达建模仿真过程中的应用实例,验证了基于XML的代码生成工具可减少重复代码编写,降低因手工编写带来的编码错误,从而提高了代码的编写质量及效率,使大规模软件开发和维护更简便。

关键词:XML,代码生成器,程序自动化

1 技术背景和优势

1. 1 代码生成器的技术发展

自动代码生成技术[1]作为一种出现在上世纪的软件开发技术,首先出现在编译器的开发和设计之中,并在此领域获得了广泛应用。在编译器模型中,编译器前段将输入的源程序翻译成一种中间表示,后端以源程序的中间表示为输入,并产生等价的目标程序作为输出。在此编译器的后端就是编译器的代码生成部分。

在这里,自动代码生成并不是指作为编译器后端的代码生成,而是指通过生成器,读取相关的代码或文档中的定义,生成如C、C ++ 、Java、Perl、Ruby、Python及HTML等高级语言代码。

自动代码生成技术从上世纪起步发展以来,取得了长足进步。但随着计算机科学与技术的不断发展, 自动代码生成技术也越来越成熟并被广泛应用[2]。

1. 2 采用代码生成器的好处

对于软件工程师而言,代码生成技术有如下优点[3]:

( 1) 保证代码的质量。一个项目周期中大量的手写代码通常会由于软件工程师在编码时不断采用新的或更好的方法而良莠不齐。代码生成技术从编码的初始阶段创建通用模板,而通过修改模板和再次运行代码生成器来对所有已生成的基本代码修正缺陷或优化。

( 2) 保证代码的一致性。由代码生成器生成的代码在API和变量名上的写法完全一致,这就为使用者提供了易懂易用的接口,更利于分层思想的实现。

( 3) 产生代码的高效性。一旦模板等设计好后, 只需简单的运行代码生成器便可高效地生成用户需求的代码。

( 4) 利于维护。接口和变量的一致性有利于后续的维护工作。

2 代码生成工具的框架

一般而言代码生成器有着必不可少的3要素: ( 1) 模板。即生成代码的格式和结构模板。( 2) 元数据。即在代码中需建模的结构相关资源。( 3) 业务规则。用于指定元数据和行为的规则,这一部分通常封装在代码生成器中[4]。

常见的典型代码生成方式有3种: ( 1) CORBA中间件所采用的IDL( 接口定义语言) 的代码生成方式。 ( 2) . NET提供的Code DOM机制。( 3) 基于XML的生成方式。表1列出了3种方式采用的模板、元数据、业务规则[5]。

由表1可看出,这3种代码生成方式各有不同,但就实现的简易程度而言,基于XML的代码生成技术明显更具优势。其以XML技术和XLST文档转换技术作为支持,而XSLT语言则直接定义文档转换规则,与生成代码采用的语言无关,故可更方便快捷地实现代码的自动生成; 而其他两种代码生成方式由于其业务规则与要生成的代码语言相关,而生成某种特定语言, 其映射关系的建立一般不由程序员确立[6]。

另外,从发展前景来看,XML具有良好的可读性, 方便的可扩展性,数据内容与其形式的分离,可轻松地跨平台应用,适合面向对象的程序开发等多方面优势。人们可通过DOM或SAX等技术对XML数据进行访问; 更可通过XPath和XSLT对其进行文档转换,将其转换为其他格式的文档。

基于以上的自动代码生成方式的对比及XML的应用优势,文中选择基于XML的代码生成方式来实现代码生成。

基于XML的代码生成方式是一种常见的典型代码生成方式。其模板语言一般为XSLT; 其元数据一般用XML文件记录; 其业务规则一般通过XSLT转换语言定义,通过XSLT引擎自动产生代码[7]。基于XML的代码生成工具的整体框架,如图1所示。

图1是具体的代码生成工具的框架。其中,数据文件即三要素中的元数据; 模板文件即模板; 而业务规则被封装在代码生成工具中。基于XMl的代码生成工具中的数据文件和模板文件均为XML表,代码生成工具则依赖于XML解析器的实现[8]。

3 代码生成工具的实现

由于在雷达系统建模与仿真中存在众多的代码重复编写的问题,为避免人为编写带来不必要的麻烦和错误,文中使用基于XML的代码生成工具来自动帮助生成底层仿真模型代码。为对XML数据进行访问,设计了一个适合于C /C ++ 的基于DOM解析规则的XML解析器。在现有开源软件CMark Up的基础上,为适应遍历普通树的各个节点的需求,文中对CMark Up进行了二次封装,重新设计了数据结构,其结构如下:

Typedef struct xml Elem_tag

{

/ / 节点操作

struct xml Elem_tag * parent; / / 父节点

struct xml Elem_tag * current; / / 当前节点

struct xml Elem _tag * child Head; / / 子节点的头

结点

struct xml Elem_tag * forward; / / 前向指针

struct xml Elem_tag * next; / / 后向指针数组

/ / 数据操作

char * attrib Head; / / 属性指针头结点

int n Attrib; / / 属性数目

/ / 节点内容

char elem Name[MAXLENGTH + 1 ]; / / 节点名称,MAXLENGTH为一个宏

int n Depth Elem; / / 当前节点的在树形结构中的深度

} xml Elem,* pxml Elem;

重新设计后的XML解析器可更容易的进行递归遍历,方便解析XML数据。

对于代码自动生成工具中重要的模板设计,为适应雷达系统建模与仿真的需求,将模板信息分为5大类: ( 1) 系统信息。代码生成后的存放路径、代码生成后的文件名、生成C ++ 代码的类名、成员函数名等。 ( 2) 参数信息。时宽、采样频率、发射功率、带宽、脉冲重复周期等。( 3) 模型的输入信息。发射信号脉冲重复周期类型、发射信号载频类型、发射信号调制类型、发射信号中心载频等。( 4) 模型的输出信息。输出数据结构体、输出信号类型。( 5) 模型之间的连接信息。两个模型之间的连接关系,两个模型之间的数据传输。

同时为生成C ++ 代码,必须为头文件( . h) 和源文件( . cpp) ,分别设置模板。为方便管理,将其放在同一XML表中以”template_h”和”template_cpp”节点区别,如图2所示。

图 2 XML 模板的设计与实现

图 3 数据文件交互式界面

为更人性化、交互性更好,给该数据文件配备了可视化的界面,如图3所示。在用户填入需要一些数据后就可点击“选项”页面的“生成C ++ 代码”按钮即可生成所需要代码。假设文件名填入“sub Transmitter”其他为默认值,生成代码:

/ / 参数定义模块,主要完成对参数的定义

typedef struct para_sub Transmitter_tag

{

double tau; / / 脉冲宽度

double fs; / / 采样频率

double band; / / 带宽

double pt; / / 发射机瞬时功率

} para_sub Transmitter; / /参数定义部分

/ / 接口定义模块,主要完成对接口的定义

typedef struct io_sub Transmitter_tag

{

/ / 输入接口定义

int in_prt Type; / / 发射信号脉冲重复周期类型

int in_fc Type; / / 发射信号载频类型

int in_mod Type; / / 发射信号调制类型

int in_mod Phase Type; / / 发射相位信号调制类型

/ / 输出接口定义

struct signal out_struct; / / 发射信号结构体

struct pmat Matrix pout_msignal; / / 发射信号

} io_sub Transmitter; / /接口定义部分

typedef struct sub Transmitter_tag

{

para_sub Transmitter para Data; / / 参数结构体

io_sub Transmitter io Data; / / 输入输出结构体

struct sub Transmitter _ tag * pm _ data; / / 指向自己的指针

} sub Transmitter,* psub Transmitter; / /用户模型 定义

4 结束语

基于XML的代码生成工具可减少重复代码的编写,降低因手工编写所带来的编码错误,提高代码的质量和编写效率,从而使大规模软件开发和维护更便捷。

代码自动生成器 篇2

当前,智能终端的普及使得移动应用的需求量不断增长。安卓作为免费、开源的手机平台受到广大开发人员及用户的青睐。安卓应用开发者大多采用传统的方式(由设计至编码),基于集成开发环境(例如Eclipse、Android Studio、Visual Studio等)完成应用的开发工作。在这些工具中,开发者需要为安卓应用的每一项组成部分进行设置或编码,包括应用界面的设计(编写layout文件,或直接通过可视化开发方式进行设计)、核心配置文件的定义(填充Androidmanifest.xml文件)、组成应用的构件的开发(Activity、Service等代码的编写)、构件间跳转关系的实现(Intent代码的编写)等。这些工作可能花费开发者较多的时间。然而,与应用框架相关的部分代码与配置文件具有类似的模式,我们认为这部分的开发工作可以通过复用及定制的方式从而提高应用的开发效率。

针对以上目标,本文提出一套借鉴MDA思想的方法,基于安卓应用的描述来完成安卓代码框架部分的自动生成。MDA指首先建立抽象的、与具体技术无关的模型,随后从抽象模型自动生成应用程序的过程[1]。遵循该过程,本文首先提出一种描述安卓应用的元模型,元模型定义了组成安卓应用的各类元素及其依赖关系。特定安卓应用的模型基于元模型标准,定义了应用的架构,包括名称、属性以及约束关系等。同时,本文方法还提出了一套应用代码模版,其中内嵌了与特定应用相关的可变、可定制的代码部分。在描述应用的模型以及代码模板的基础上本方法涵盖了从元模型所描述元素到代码模版中可变部分的映射过程,支持通过代码生成器自动生成安卓应用的框架,随后开发者可将精力投入在应用业务逻辑的代码编写上。基于本方法,我们实现了安卓应用框架自动生成工具,工具采用GMF[2]图形框架支持用户以可视化的方式设计应用框架,A-pache Freemarker[3]代码生成器负责定制模版,生成应用代码框架。

1 相关工作

近年来,针对基于MDA的代码自动生成技术的研究主要包括UML模型的代码自动生成、模型驱动的安卓界面(Graphical user interface)自动生成、基于DSL(Domain Specific Language)元模型以及采用BPMN模型的代码自动生成。

为了提高GUI的开发效率,Silva等[4,5,6,7,8,9,10]提出了面向安卓界面自动生成的模型。他们为安卓应用的控件、窗口、事件监听器等建立抽象模型,再将模型转换为代码,自动生成安卓应用界面的代码。本文的研究重点在于创建描述安卓应用的模型,自动生成应用的代码框架,而界面自动生成并非本文考虑的重点。本文仅通过配置实现了简单的线性布局。

在基于UML模型驱动的代码自动生成方面,Parada等[11]采用了UML类图和顺序图为安卓应用建立模型,并建立类图与顺序图的对应关系,然后结合两者自动生成安卓应用代码框架。Kraemer等[12,13]采用UML活动图描述安卓应用,将活动图转换为可执行的状态机,再自动生成安卓应用的代码。由于安卓应用的领域特征,UML统一建模语言不能很好地描述安卓应用,因此本文采用了领域特定的元模型定义组成安卓应用的各类元素。

在DSL的元模型的模型驱动技术方面,Lachga等[6,7,8,9,10]借鉴MDA思想,提出了DSL的建模语言,并开发了安卓界面代码自动生成工具。Madari等[8]为应用的GUI和页面跳转做详细设计,建立了应用整体与不同页面的模型,再将页面之间的跳转通过CR模型(UML活动图)联系起来。本文的元模型定义了组成安卓应用的各类元素,如Activity、Service、Broadcast Receiver等,并通过描述应用的模型为安卓应用的框架建模。

其他研究人员采用BPMN建模语言为应用建模,例如SolisMartinez等采用BPMN建模语言来描述业务流程,然后生成跨平台的应用[14,15]。模型通过XML格式定义流程模型,经过一定步骤的配置后,实现了与平台无关的应用(Android、IOS)。但他们并没有对具体的应用开发做出详细阐述,仅提出了平台无关的模型。

此外,一些知名公司开发了图形化工具为开发人员带来便利。例如,谷歌与MIT联合开发的一款安卓快速开发工具App Inventor[16],该工具可以使用户通过基于浏览器的工具开发手机应用。用户可以方便地拖放代码块,通过mushup的方式将它们放在一起,产生一个应用程序。由于是由特定的模块组成的,所以具有一定限制性。IBM公司的Rational Rhapsody[17]提供了用于安卓代码框架生成的Eclipse插件,该工具采用UML类图、顺序图为应用建模。但是,该工具的模型配置比较复杂,与代码开发几乎是一一对应的。相比而言,本文提出了领域特定的元模型,并通过描述应用的模型为安卓应用建模,建模过程更加简单直观。

2 描述安卓应用框架的元模型

2.1 元模型适用范围

由于安卓四大组件包括Activity、Service、Broadcast Receiver和Contentprovider[18],每种组件都具有自己的生命周期,承担不同的职责。对于多数应用开发层的应用而言,都由以上四大组件构成,例如业务信息类应用、社交软件、新闻应用等。本文提出的元模型将安卓组件设计为元模型的元素,可适用于多数安卓应用开发程序。而本文提出的元模型对于诸如框架开发类应用(基于安卓操作平台做定制化开发)、底层开发类(驱动开发、JNI)等尚不适用。具体来说,本文提出的元模型可适用于具有以下特征的应用:

(1)安卓应用包含许多Activity。Activity主要用于显示界面、与用户交互;应用需要实现导航功能,导航指Activity之间的跳转。

(2)安卓应用需启动后台服务。Activity是安卓应用的主线程,为了保证用户交互流畅,Service可以用于完成长时间执行的后台服务,例如下载文件、播放背景音乐等。

(3)安卓应用需要监听全局广播。例如,应用需要监听系统广播,如检测Wi Fi、开机启动、sms消息等。

(4)安卓应用需要实现组件间通信,我们可以通过绑定服务、动态广播实现组件间的通信功能。

2.2 元模型定义

描述安卓应用的元模型定义了描述安卓应用框架的各个元素及其依赖关系,如图1所示。

表1给出了具体的元模型的定义,我们将元模型元素按照类别分为组件类、Widget类、事件监听器类、关联类和权限类。

2.3 元模型依赖关系定义

元模型的依赖关系主要分为以下五个方面:

(1)Transition与Event Listener、Intent依赖关系定义

安卓应用组件之间的转移是由事件驱动并由Intent负责传递消息,因此Transition与Intent、Event Listener具有关联关系。

(2)Component转移依赖关系定义

我们把Component元素之间的依赖关系定义为Transition元素。Activity元素可以跳转到多个其他的Activity;Activity可以启动多个Service;Component元素可以向多个广播发送通知。Transition必须设置好相应广播的action属性,否则广播将接收不到通知。

(3)Activity、Widget、Event Listener依赖关系定义

Activity可以包含多个Widget组件,所以Activity与Widget具有一对多的聚合关系。同样,Widget组件可以触发不同的事件,因此Widget与Event Listener也具有一对多聚合关系。

(4)Activity与Broadcast Receiver依赖关系定义

动态广播是安卓应用开发中实现跨进程通信的常用技术。在Activity中可以动态注册Broadcast Receiver。Activity元素与动态的Broadcast Receiver元素具有一对多聚合关系。

(5)Widget与相应的常用事件监听器依赖关系定义

每种安卓控件都具有与常用事件监听器。

3 基于模版的框架代码生成

3.1 基于Freemarker的代码模板

本文采用Freemarker模板引擎自动生成安卓应用的代码模板。Freemarker遵循MVC(model view controller)模式,是一款轻量级的代码生成引擎。Freemarker模板引擎的语法规则类似于脚本语言,本身也具有一些编程能力,例如条件判断、循环嵌套、集合等概念类似于其他编程语言。例如,${}指令表示可以替换为某个变量的值,if/elseif/else表示条件判断,list指令表示循环遍历对象集合,include指令表示嵌套子模板等。本文按照Freemarker的语法规则定义了源代码、布局、配置模板。其中,源代码模板包含了Activity模板、Service模板、Broadcast Receiver模板。在这些模板中,还可以设置内嵌子模板,例如控件模板、Intent模板、bind Service模板等。图2展示了上述模板和各个模板之间的依赖关系。

本文定义的模板类型非常多,由于篇幅的限制,我们仅展示了其中的一个模板。图3展示了Activity模板,Activity模板主要用于生成Activity类的代码框架,包括引入包、继承Android.app.Activity类、重写Activity的生命周期方法。同时,在on Create方法中设置该Activity的布局文件、注册动态广播。在on Destory方法中,释放绑定的Service,并且取消注册动态广播。图中的高亮区域显示了代码模板的可变部分。Activity模板中可以包含多个widget、动态广播,还可以绑定多个Service。我们将这部分可嵌套的模板定义为子模板,实现了模板之间的包含关系。例如,在on Create方法中调用<#include"/Button.ftl">可以在Activity模板中嵌套Button模板。此外,在事件中还可以嵌套Intent模板从而实现Component元素之间的关联关系。

3.2 基于描述模型的代码模板定制

在前文所提出的元模型与代码模板的基础上,我们按照以下转换过程实现框架代码的自动生成,如图4所示。首先,创建基于元模型标准的描述应用的模型,得到模型的XML描述文件。基于Freemarker的模板规则定义一组代码模板,包括安卓应用的源代码、布局、配置文件、子模板等。接着,将XML描述文件和代码模板作为代码生成器的输入。随后,将描述应用的模型映射到代码模板的可变部分,最后生成应用的代码框架。

其中,应用的源代码是应用程序的主体,根据模型和代码映射规则生成的源代码包括用户定制的Activity类、Service类、Broadcast Receiver类。Android Manifest.xml配置文件可以定义用户所配置的版本,注册Activity、Service、Broadcast Receiver、Permission等。Layout布局文件是安卓应用程序的界面。我们的工具会根据模型和属性配置,自动为Activity生成相应的布局文件。图5展示了一个简单的示例,形象地展示了从特定模型到模板中可变部分的映射过程。

由于模型的XML定义文件是XML DOM树形式的,我们引入了Dom4j API解析该模型的定义文件,遍历读取该定义文件中的各个节点、属性。同时,为其中的节点建立了Java模型与之一一对应。通过遍历该XML文件,可以得到模型所创建的所有节点。根据Node节点的类型分类,将每个Node节点独立作为一个源文件的输出。例如,XML文件中包含Broadcast Receiver元素,将它注入Broadcast Receiver对象,然后生成对应的java源文件。对于类型是Activity的元素,生成它所包含的组件、事件监听器、布局文件以及生命周期等。如果元素的类型是Service,那么根据他的启动类型,判断是否要绑定Service。对于Broadcast Receiver,判断它是否是静态等还是动态的。如果是静态的广播,那么需生成独立的Broadcast Receiver文件,并在配置文件中注册,否则在代码中动态注册。

4 工具实现与实验

基于上述元模型,实现了Android应用框架自动生成工具。本节首先介绍了工具的架构设计。接着,我们使用该工具实现了一个具体的安卓应用“EBook”,并且展示了运行效果。

4.1 Android应用框架自动生成工具

Android应用框架自动生成工具的主要任务是开发一套能为安卓应用创建描述应用的模型的图形编辑器和自动生成应用代码框架的功能。工具架构主要分为五层,分别为Eclipse Platform、Platform Runtime、Tool Framework、工具层和应用层,如图6所示。

最底层的Eclipse Platform层代表Eclipse运行时环境。Eclipse是一个开源的平台,可以使各种功能以插件的形式自由组装的IDE,例如GMF、Draw2D、Android ADT等。Android ADT[19]为开发安卓项目提供了运行时环境。工具框架层提供了图形工具框架、Dom4j XML API、Android SDK所提供的API、代码生成器。本文采用了Apache Freemarker代码生成技术定制代码模板,并且在运行时动态输入数据模型自动生成不同的代码。工具层包括了图形编辑器,该图形编辑器是在GMF的基础上生成的,可以利用该编辑器创建描述安卓应用的模型。工具层还包括我们定义的代码模板、元模型所描述元素到代码模板中可变部分的映射过程、Android工程。我们首先通过EMF[20]创建描述应用的EMF元模型,为了使工具建模更加方便、形象,在元模型的基础上加入了描述流程的节点如Process、Node、Start、End、Edge、Permissions。我们会在模型映射到代码模板的定制过程中,从中提取出符合元模型定义的元素,再将模型转换为最终的代码。然后利用GMF图形框架自动生成描述安卓应用的编辑器。随后,按照Freemarker的模板语法规则定义好安卓应用的代码框架、布局、配置文件。接着,将特定的模型与代码模板的可变部分做映射,完成模型到代码的转换。工具架构图的最上层是应用层,通过该工具,可以快速为安卓应用建模。

4.2 实验案例

EBook是一个简易的电子书应用,提供书籍列表、下载书籍、我的书籍、查看书籍内容的功能。EBook的架构包括手机客户端和服务器端。用户可以在手机客户端下载、翻阅电子书。服务器端则为客户端提供书籍的下载。

我们将使用Android应用框架自动生成工具生成应用的基本框架,再手动编写具体的业务逻辑代码以及服务器代码等。应用包括三个界面Book List Activity、My Book Activity、Book Content Activity。Book List Activity页面提供许多未下载的书籍,通过列表的形式列出,用户可以点击列表中的书进行下载。进入MyBook Activity可以查看已下载的书籍列表。点击已下载的书籍列表可以查看书籍的内容和信息。

4.3 实验

实例应用需将Book List Activity设置为起始界面,在BookList Activity中实现Button、List、Menu、Text View以及动态广播。然后,为Button、List加入点击事件监听器。在点击List时启动一个后台的Down Load Service来完成下载书籍的工作。下载完成之后发送Intent到动态广播,告知用户下载已完成。在点击该Button之后跳转到My Book Activity界面。My Book Activity包括一个Text View和一个List。List列出了所有已下载的书籍,点击List可以进入第三个界面Book Content Activity。此外,我们还为实例应用添加了安卓应用的常用权限存储卡访问权限、震动权限、Internet访问权限。存储卡访问权限用于保存、读取已下载的书籍。Internet访问权限主要用于下载书籍时访问互联网。震动权限用于发送消息给用户时震动提示用户下载完成。

使用Android应用框架自动生成工具生成实例需要创建一个新的Android工程,并在工程目录下创建应用的模型文件。然后拖拽右侧工具栏的模型元素,定义应用的模型节点和关联关系,例如设置组件之间的跳转,以何种方式启动Service,实现发送广播等。随后,在属性视图完成每个节点的属性定义。最后,使用代码自动生成功能将模型转换为代码,从而得到应用的代码框架,如图7所示。

在完成了上述配置后,通过代码自动生成功能可以得到工具自动生成的应用代码框架。我们在该框架的基础上手动添加了业务逻辑代码并且美化了界面。图8显示了EBook的运行效果,图中展示了应用的界面,包括书籍列表、我的书籍、查看书籍内容和版本信息界面。查看书籍内容界面则显示了某一本图书的内容。

5 结语

本文借鉴MDA思想提出了描述应用的元模型。同时,我们定义了代码框架模板并且提出了从元模型所描述元素到代码模板中可变部分的映射方法。基于本文提出的元模型,实现了Android应用框架自动生成工具。该工具可以为安卓应用创建描述应用的模型,生成应用程序的框架,包括源代码、配置文件、布局文件。实验部分通过一个实例演示了Android应用框架自动生成工具的功能。通过实验,体现了Android应用框架自动生成工具可以为开发人员快速构建应用模型,自动生成应用的代码框架。在此框架的基础上继续开发能够有效提高应用开发效率。

代码自动生成器 篇3

UML已经被广泛应用于当前的软件开发中。在模型驱动开发中, 自动生成代码可以快速得到原型, 有助于早期需求和设计的验证, 对最终实现有着重要帮助;更远的目标是模型自动生成代码将可以取代手工编码, 从而提高软件开发的抽象层次。可是, 模型与代码之间的沟堑至今也未能填平。一方面, UML代码自动生成技术的研究方兴未艾;另一方面, UML本身也处在进化当中。当前UML2即将正式公布, 它融入了MDA的结构化开发思想。

二、结构的实现

可执行UML中以类图来建模系统的结构, 描述了对象的类型和对象间的各种静态关系。在模型-代码的映射关系中, 结构对应代码的框架部分。类图的代码生成技术比较成熟, 它的各种成分 (属性、方法、继承、关联、聚合等等) 都有明确直观的映射关系, 这里不讨论细节, 而是给出结构实现的总体方案, 其中的策略和技术同样适用于约束和行为。

一个系统, 不论是模型形态还是代码形态, 不同的只是承载信息的格式即具体语法, 相同的是其中蕴含的信息即语义。从这个意义上说, 代码生成的过程就是信息改变承载格式的过程。信息的承载格式分为四层, 分别是UML模型层、XMI模型层、树模型层、代码层。分层可以屏蔽复杂性, 提高各层的可重用性。

三、约束的实现

约束是系统的限制条件, 用来保持结构的特性和控制动作的活动时机。可执行UML用OCL表达式精确的刻画约束。OCL可以弥补图形表达的不足, 使得UML模型更加精确;作为一种基于集合操作的声明式语言, 使得UML模型更加形式化。

可执行UML中的OCL约束分为三类:约束属性, 即以不变式限制类的属性;约束方法, 即用前置、后置条件限制方法;约束行为, 即用布尔表达式刻画动作的触发条件。建模中, 前两类OCL约束在类图中定义, 第三类则在行为模型如序列图、状态图中定义。第三类约束在讨论序列图的时候研究, 先讨论前两类约束的代码生成。

以一个简单的例子来说明几种典型的OCL表达式的代码映射思路。有两个类Person和Company, 其中的约束非形式化的表述如下:

C1.人的年龄必须大于等于1C2.已婚的人年龄必须大于等于18

C3.所有公司雇员的年龄必须大于18 C4.存在一个叫Jack的雇员

C5.只有在员工数小于100时才雇佣新人C6.雇佣成功后员工数增1

分析约束C1到C6的OCL表达式不难发现:布尔表达式是共同的成分, 类型和句式则不尽相同。在映射关系中, 布尔表达式直接对应一个代码片段, 具有式4_1的形式;类型和句式则决定这个代码片段的插入位置。

if (Boolean expression==false) throw except ion式4_1

C1―C6本质上都是对属性的约束, 如果具有改变某属性值能力的相关方法都遵循该属性的约束, 那么我们就说约束得到了实现。于是这些相关方法也就是约束代码片段的插入点。前后置条件是一种局部约束, 作用域仅在其所属方法内, 插入位置分别在方法的开头和结尾。所以C5和C6分别对应成员函数hire实现中开头和结尾的两条if语句。不变式是一种全局约束, 作用于对象的整个生存期, 插入点是全部相关方法。C1和C2约束的相关方法是Person类的构造函数, 故此在构造函数中应当添加两条if语句, 以保证创建的Person对象是合法的。C3和C4通过关联关系约束了雇员的某些属性, 而建立链结的是hire方法, 所以在hire的实现中加入两条if语句。所不同的是每一次调用hire方法时, C3的实现是敏感的, 即一旦行参的属性违法就立刻抛出异常;而C4的实现是迟钝的, 只要hire方法还能执行 (total Num<100) 就认为合法, 但用一个标志位来记录约束是否得到了满足, 只在最后一次hire方法执行时才检查标志位, 不满足则抛出异常。出于自动生成代码的需要, 我们应先建立属性和方法之间的依赖关系, 因为依赖于被约束属性的那些方法就是约束的相关方法。这里我们说一个方法依赖于某个属性, 如果该属性以左值的形式出现在这个方法实现的赋值表达式中。由于属性的改变一般都在算法中进行, 所以一种选择是在建模算法时明确的指出这种依赖关系。另一个选择是静态分析方法实现体的代码, 由算法建立这种依赖关系。

摘要:UML模型的代码自动生成是模型驱动开发中的一个关键问题, 对早期需求、设计的验证和最终实现有着重要帮助。本文系统研究了模型的代码自动生成技术, 并给出了带OCL约束的类图的实现。

关键词:模型,代码生成,约束

参考文献

代码自动生成器 篇4

高性能并行计算是现代科学研究、工程技术开发和大规模数据处理的关键技术,而并行编译系统是并行计算机系统软件中十分重要的一部分,提高并行编译技术对充分利用并行机资源和提高并行机效率起着十分重要的作用。

并行编译器包括前端处理和后端处理两部分:前端处理主要包括逻辑上的并行识别、计算和数据划分、依赖关系识别;后端处理主要是并行代码的自动生成,代码生成的关键在于如何高效地生成同步通信代码。

并行程序中的通信主要由四部分组成:数据初始分布通信、计算前的数据准备通信、计算过程中的同步通信以及数据收集通信。初始数据分布通信是在进行数据的初始分布过程中引起的通信。由于初始分布中数据划分和计算划分不能做到完全对齐所引起的通信称之为数据准备通信。同步通信是在进行并行计算过程中产生的通信。数据收集通信是所有进程计算结束后,主进程把所有进程的计算结果收集起来得到程序的最终执行结果时所引起的通信。本文重点讨论计算中的同步通信问题。

在文献[1]中对代码生成和通信优化做了介绍,但对具体如何实现没有讨论,本文则提出利用命名的线性不等式系统来表示数组数据空间、循环迭代空间、虚拟处理器空间和物理处理器空间,并建立了它们之间的内联关系,在此基础上给出了同步通信代码的自动生成算法。

1 计算划分

在分布式存储的大型计算机中,循环级的并行性一般是通过对循环嵌套迭代空间进行计算划分并将循环迭代分布到多个进程同时执行来实现的。下面给出与计算划分相关的定义。

定义1 迭代空间 迭代空间I表示一个循环边界是循环索引的线性函数且深度为m的循环嵌套,该空间是一个m维多面体。循环嵌套的每个迭代对应多面体中的一个整数点,即一次计算操作,用索引向量undefined表示。

定义2 处理器空间P 处理器空间P表示一个n维的处理器数组。

定义3 计算划分[4]C 计算划分undefined是满足特定关系的迭代和处理器对undefined的集合,处理器undefined执行迭代undefined当且仅当undefined。其中U是一个扩展的幺模矩阵,undefined是整数向量,B是整数矩阵,undefined是符号向量,undefined。

在计算划分C中,U指示计算划分是对迭代空间的哪些维进行划分以及是正分还是斜分;undefined给出分块的大小;undefined是偏移的大小。计算划分在代码生成的前一遍自动生成。

2 读写依赖关系与LWT树

计算中的同步通信由读写依赖关系和计算划分共同确定,对依赖关系有如下定义。

定义4[5] 嵌套循环L中的语句T的一个实例T(j)和语句S的一个实例S(i),如果存在一个存储单元M满足下述条件,则称语句T的实例T(j)依赖于语句S的实例S(i):

(1) S(i)和T(j)都引用(读或写)M;

(2) 在程序串行执行时,S(i)在T(j)之前执行;

(3)在程序串行执行时,从S(i)执行结束到T(j)开始执行前,没有其他实例对M进行写操作。

一对语句实例可以用4种不同的方式引用相同的存储单元,因此有4种类型的依赖关系:

① 如果S(i)写M而T(j)读M,则T(j)流依赖于S(i);

② 如果S(i)读M而T(j)写M,则T(j)反依赖于S(i);

③ 如果S(i)写M而T(j)也写M,则T(j)输出依赖于S(i);

④ 如果S(i)读M而T(j)也读M,则T(j)输入依赖于S(i)。

在这4种依赖关系中,④不会影响程序的并行化,不会引起通信,②和③的依赖关系是可以消除的,也不会引起通信,只有①需要通信,本文中的同步通信即指由流依赖所引起的通信。

在进行依赖关系分析时,用LWT树来表示数据之间的读写关系,每对读写对对应一棵LWT树。LWT树是一棵二叉树,表示精确的数据流信息,是描述从读操作实例到提供该读操作所读数据的最后一次写操作实例的映射关系。若读、写分别用循环索引undefined和undefined表示,则该函数的定义域是所有满足循环边界限制的undefined的集合。LWT树包括根节点、叶节点和内节点,内节点是对读undefined进一步的限制,叶节点又分为⊥节点和非⊥节点,表示了不同的依赖关系。

LWT[3]树把循环嵌套划分为以其每个叶节点的内容(contexts)ι为元素的集合,undefined。如果一个contextι∈I中迭代所读的值是在循环中产生的,则存在最后写关系undefined,且读迭代undefined所读值在写迭代undefined中产生},其中undefined和undefined是线性函数。

对给定的读迭代,从LWT知道一个写迭代undefined修改了undefined所读的数据且undefined是修改该数据的最后一个写操作,因此可以定义一个写迭代和读迭代之间的函数来表示undefined到undefined之间的关系,记为L,这样就可以通过LWT计算出两次引用之间的数据流依赖向量。

定义5 最后写关系LasarLasar是从读数组访问undefined和读迭代undefined到写数组访问undefined和写迭代undefined的映射,undefined当且仅当undefined;undefined;undefined;undefined且undefined使得undefined;undefined;undefined,其中undefined和undefined是读写访问函数。

由定义5知道,如果写迭代undefined和读迭代undefined都访问同一数组元素undefined之前执行,而且在undefined之间不存在其他迭代修改数组元素undefined则undefined之间存在最后写关系。

通过建立LWT树的方法可以将依赖关系精确到具体数值,这就为各进程之间的通信提供了关键依据。依赖关系分析是在代码生成的前一遍自动生成的。

3计算代码和计算中同步通信代码的自动生成

在并行程序代码自动生成中将涉及到多个多维整数空间,包括数组数据空间、循环迭代空间、虚拟处理器空间和物理处理器空间等。定义1和定义2分别给出了循环迭代空间和处理器空间的定义,下面给出数据空间的定义:

定义6 一个m维的数组A[n0][n1]…[nm-1],li≤ni≤ui,0≤i≤m-1,定义了一个m维的数据空间,该空间每一维的上下界即是数组每一维的上下界li和ui。

用命名的符号系数不等式系统统一表示这些空间,该不等式系统由多个不等式组成,每个不等式表示一种变量之间的关系,每个变量表示的即是空间的某一维。变量的所有可能的整数解的集合用n维离散的笛卡尔空间表示(n是变量数),所有满足该不等式系统的解都与笛卡尔空间中的一个整数点相对应。

计算代码和同步通信代码的自动生成过程分三部分:生成数据的接收和解包代码、生成计算代码、生成数据打包和发送代码。自动代码生成的关键是在程序的什么地方插入何种方式的通信代码?首先判断是否需要进行同步通信,如果LWT树中读的数据不在当前进程则需要通信,且利用计算划分来确定应该与哪个进程进行通信。

定理1 计算划分C满足最后写关系μ的通信集是undefined的集合,其中,undefined。

定理1所处理的是LWT树中的非⊥节点,根据LWT提供的读写依赖关系和读写变量所在

迭代的取值范围以及计算划分来判断两个迭代之间是否需要进行通信,见图1[1]。从图中可以看出,读/写迭代通过计算划分C分布到不同的进程pr和ps,两者之间通过LWT树联系在一起,若undefined则需要通信。

对于每一个物理进程mypid,通过以下算法判断是否需要发送数据给其他进程。

算法输入:计算划分C、依赖关系LWT、处理器空间P、迭代空间I

算法输出:并行同步通信代码和计算代码

算法描述:

(1) 建立虚拟拓扑结构把当前进程的标识mypid转换为多维坐标表示的pids;

(2) 通过计算划分和循环迭代范围得到参与计算的进程范围Pe;

(3) 如果pids∉Pe则不需要通信,否则;

(4) 根据计算划分C得到pids的迭代范围is;

(5) 根据LWT树中非⊥节点提供的读写依赖关系信息得到与is对应的ir;

(6) 依据ir和计算划分C得到ir所在的进程pidr;

(7) 比较pidr和pids是否是同一进程,如果二者相同则不需要同步通信,否则;

(8) 产生同步发送代码:打包数据并发送给pidr。

相应的,进程也需要判断是否需要接收其他进程发送来的数据:

(9) 通过建立的虚拟拓扑结构把当前进程的标识mypid转换为多维坐标表示的pidr;

(10) 通过计算划分和循环迭代范围得到参与计算的进程范围Pe;

(11) 如果pidr∉Pe则不需要通信,否则;

(12) 根据计算划分C得到pidr的迭代范围ir;

(13) 根据LWT树中非⊥节点提供的读写依赖关系信息计算出ir对应的is;

(14) 依据is和计算划分C得到is所在的进程pids;

(15) 比较pidr和pids是否是同一进程,如果二者相同则不需要同步通信,否则;

(16) 产生同步接收代码:接收pids发送来的数据并解包数据。

最后生成计算代码,根据上一遍提供的计算划分C和循环迭代I的边界信息计算出执行计算的进程范围,再依据分块执行的原理把计算分布到各进程执行。

4 实例分析

以下例来说明上面的算法:

例1 for(i=0;i<=N-1;i++)

for(j=i;j<=N-1;j++)

for(k=N-1;k>=i;k--)

a[j][k][i]=a[j][k][i]+a[i][k][j]*a[j][i][k]/a[i][j][k];

该例计算划分C:pid0=-k,pid1=i;迭代空间I:0≤i≤N-1;i≤j≤N-1;i≤k≤N-1,LWT树见图2。从图中可以知道数组引用a[j][k][i]和a[i][j][k]之间存在读写依赖关系,其依赖关系为:ks=-jr;js=ir;is=kr。

设N=4,则由计算划分C和迭代空间I可以计算出虚拟处理器空间P为-3≤pid0≤0,0≤pid1≤3。在生成同步通信代码时,首先判断是否需要进行通信,如果需要通信则产生同步通信代码。以pidr0=-2,pidr1=1为例来说明,根据计算划分C知道ir=1;kr=2;ir≤jr≤3,进而根据LWT树提供的读写依赖关系得到is=2;js=1;-3≤ks≤-1。得到写迭代之后,再根据计算划分C就可以找到该写迭代所在的进程为-3≤pids0≤-1,pids1=2。最后比较pids和pidr是否是同一进程,不是则产生两个进程之间的同步通信代码。此例pidr≠pids,则两个进程之间需要通信,进程pids产生同步发送代码,进程pidr产生同步接收代码。

5 总结与展望

本文主要讨论串行程序并行化中涉及到的计算代码和计算中同步通信代码的自动生成。文中所介绍的算法已在SUIF编译架构上实现,并利用ppopp benchmark程序集进行了验证,实验结果表明该算法能够正确生成计算代码和同步通信代码,但在该算法中未对同步通信的优化进行处理。下一步将主要研究计算中同步通信的优化问题,如多维并行条件下的计算和通信的重叠等。

摘要:简要介绍了并行编译中的计算划分和依赖关系分析,提出如何利用计算划分和依赖关系自动生成并行程序中的计算代码和同步通信代码。

关键词:计算划分,依赖关系,最后写树,同步通信

参考文献

[1]Amarasinghe S P,Lam M S.Communication optimization and CodeGeneration for distributed memory machines.In the Proceedings of TheACMSIGPLAN′93 Conference on Programming Language Design andImplementation,Albuquerque,New Mexico,June,1993:126-138.

[2]Ferner G S.The Paraguin compiler Message-passing code generation u-sing SUIF.In the Proceedings of the IEEE SoutheastCon 2002,Colum-bia,SC,April 5-7,2002:1-6.

[3]Maydan D E,Amarasinghe S P,LamMS.Array data-_flowanalysis andits use in array privatization.In the Proceedings of ACMSIGP-LAN-SI-GACTSymposium on Principles of Programming Languages.Charles-ton,South Carolina,January 10-13,1993:2-15.

[4]Anderson J M,Lam M S.Global Optimizations for Parallelism and Lo-cality on Scalable Parallel Machines.In Proceedings of the SIGPLAN′93 Conference on Program Language Design and Implementation,June1993.

代码自动生成器 篇5

现在比较流行的代码生成方法有基于XSLT处理器的方法和基于模板的方法。XSLT定义了XML文档的转换语言,采用XPath对XML文档各部分进行定位,对XML文档的操作非常简单高效。现在大部分的代码自动生成系统采用的都是基于模板的方法。基于模板的方法就是把静态内容抽取成模板,把动态内容用特殊标记嵌在模板页面里面,利用模板引擎将动态标记赋值,即可生成按照模板定制的具体文件[2]。基于这种技术的工作过程是:代码生成器读取一个抽象需求的定义作为输入,然后根据规则将模板变量进行替代,再根据模板产生基于该需求的一个或多个文件。因为模板能够容易的改变而不会反过来影响模块和模块工具。这种方法为代码生成提供了快速的开发周期。为代码生成创建基于平台的模型的方法能够随要求的变化而快速的改变,而不会对应用程序模型带来任何不良后果。所以本文采用这种方式来实现代码的自动生成。

1 代码自动生成系统的设计

基于J2EE平台的代码自动生成工具主要是生成java类文件、数据访问对象(DAO)文件、持久层配置文件、表单映射文件、jsp文件等等。代码自动生成系统的输入可以是UML模型、数据库模型等。它的总体设计思路是:通过第三方的建模工具(例如MagicDraw UML),将UML表示的类图用XMI格式表示。XMI格式的文件保留了类的一些基本属性,例如类的属性,方法,关系等,是原始类的XML化的结果。然后通过解析所生成的XMI文件,可以获取类的相关信息,并将之存储在Java对象中。最后的部分就是代码生成,将已经有的java对象与事先准备好的代码模板合并,调用freemark模板引擎,即可生成目标文件。整个代码生成工具的工作过程可以用图1表示。

3 代码自动生成系统的实现

3.1 模型的解析

文作为模型交换的标准,XMI是代码自动生成工具必需支持的模型格式,只有这样,不同代码自动生成工具所使用的模型才具备可交互性。因此,本文的工具采用XMI格式的模型作为输入。这里的XMI文件是根据类图通过工具转换而来,包含了此类图的所有信息。

设计上把XML解析类设计为一个接口IParse,里面包括getClassInfo方法和getAttributeInfo方法,分别用来取得类的信息和取得属性的相关信息。然后通过调用JDOM提供的API库,编写一个JdomParserImp类,实现解析XML文件的功能,实现IParse接口。这样设计的好处在于,搭建了一个解析器的框架,而不局限于某种具体的解析引擎技术,当以后出现更好的解析引擎时,就可以重新实现IParse接口,而不需要修改其他模块的代码。设计类的模块如图2所示。

3.2 模板库的设计

由于本文采用基于模板的代码生成方法,那么模板库是这个转换工具的底层元素。模板库的样式即为所生成代码的原型。本文采用FreeMarker模板引擎,构造了javabean的模板库。

所有的Javabean文件都有它自己固定的结构,主要包括:该类所有的属性的声明,关于这些属性的get方法和set方法。下面就是关于javabean的模板文件javabean.ftl的内容。

所以只要知道某个类的属性名和它的类型,就可以很容易地制造出该类的javabean文件。从上述javabean的模板文件可以看出,模板文件可以直观地反映要生成的代码,易于管理。如果要生成其他内容,例如持久层的配置文件,数据访问层的相关文件,只需制作相应的模板即可。

3.3 目标文件的生成

目标文件生成器设计的主要思想就是:将从XMI文件解析出来的对象填充在模板文件适当的位置。IMerge中的generate方法就是实现此功能的方法。本系统的generate方法可以有多种实现,对应各种不同平台的代码生成,各生成器只需要实现自己特有的generate方法,就可以完成自己代码的生成。对应于本文的目标平台J2EE平台,我们需要分别生成javabean文件、持久层映射的配置文件、DAO文件、formbean文件。目标文件生成的设计图如图3所示。

4 代码自动生成系统的应用

下面以一个在线考试系统为例,实现该工具的应用。在线考试系统需要保存试卷信息,包括试卷本身和它所包含的每道题目信息;还需要保存用户的答题情况,包括用户整张试卷的答题情况和每道题目的答案。所以可以得到该模块的类图如图4所示。

运行代码自动生成系统,可以将输入的UML类图转换成一系列的目标文件输出。由于篇幅有限就不一一列出所生成的代码了。将生成的目标文件部署到应用服务器,就可以直接运行了。图5显示了运行成功的获取所有试卷的jsp页面。

该在线考试系统的开发中,由于运用了代码自动生成工具,大大减少了开发人员的工作量。经统计,该工具可以自动生成75%以上的代码,只有25%不到的代码需要程序员手动添加。因为代码都是工具自动生成的,代码的质量得到了保证,项目开发周期大大缩短。本来需要分配给一个团队四个人两个月开发时间的项目,现在只需要一个开发人员和一个美工在不到一个月的时间内即可完成,充分体现了该工具的实用价值。

5 结束语

本文描述了一种基于模板的代码自动生成系统的设计和实现,并利用它完成了基于J2EE-Web应用系统的代码自动生成。有了这种工具,项目开发组长可以快速地创建系统的原型;分析阶段和开发阶段被清楚地解耦。原型系统可以让用户在早期开发阶段就有参与系统设计的机会。此外,根据用户的反馈,原型系统可以很容易地被再次自动生成[5]。实践证明,代码自动生成系统有利于标准化和代码复用,方便了代码维护和代码迁移,提高了软件开发的速度和质量。

摘要:采用代码自动生成技术能为软件开发带来代码质量的提高、开发风险的降低等优点,提高了软件开发的速度和质量。该文描述了一种基于模板的代码自动生成系统的设计和实现,并利用它完成了基于J2EE-Web应用系统的代码自动生成工作。

关键词:代码生成,模板技术,模型驱动架构,J2EE

参考文献

[1]Object Management Group.MDA Guide[EB/OL].[2008-06-15].http://www.omg.org.

[2]Herrington J.Code Generation:The one page guide[EB/OL].http://codegeneration.net/files/JavaOne-OnePageGuide-v1.pdf.2003.

[3]陈翔,王学斌.代码生成技术在MDA中的实现[J].计算机应用研究,2006(1):147-150.

[4]Kleppe A,Warmer J,Bast W.MDA explained:the model driven architecture practice and promise[M].Boston:Addison Wesley Professional,2003:25.

代码自动生成器 篇6

在软件开发的过程中,开发人员总是重复编写一些简单的代码,而且每当新技术来临,又不得不一再地重复过去的工作。同时,需求的变化也从来没有停止过[1]。为了解决这些问题,人们提出了代码自动生成技术。代码自动生成技术根据模型驱动架构MDA(Model Driven Architecture)的思想,将由开发人员描述的软件系统模型转换为代码,使得模型成为软件开发的核心制品,提升了软件开发的抽象层次,从而提高软件开发效率和软件的可维护性[2]。

统一建模语言UML是一种以图形方式对系统进行分析、设计的标准建模语言,使用UML建模可以清晰地表示系统的结构和行为信息。UML模型中的类图显示了系统中各个类的静态结构,顺序图描述了对象之间消息传递的时间顺序。因此,软件开发人员通常将二者结合描述软件系统的详细设计模型。代码自动生成就以类图和顺序图为输入,依据一定的转换规则生成具有静态和动态信息的代码。

目前关于将UML模型图生成代码的研究很多,文献[3,4]提出了一种将类图和顺序图生成具有结构和行为信息的Java代码的方法,文献[5]列出了多条顺序图到Java代码的转换规则,文献[6]提出了一种将类图生成C++代码的方法,文献[7]提出了静态模型到C代码的转换规则,文献[8]提出了一种将类图生成.Net组件代码的方法,文献[9]研究了代码自动生成技术中代码信息的来源。但对如何结合类图和顺序图生成与完整应用系统相接近的C++代码的研究却比较少。

本文提出了一种将类图和顺序图相结合生成包括静态结构和动态行为信息的C++代码的方法。

1 转换方法

图1描述了由UML模型转换到C++代码的过程框架,包括UML模型、UML元模型、代码生成器以及C++代码。UML模型包括语法正确的类图和顺序图,用来描述软件系统的静态结构和业务逻辑信息,由编程人员绘制。UML元模型包括类图、顺序图的元模型,用来定义类图、顺序图的绘制规则。代码生成器的核心是代码转换规则,转换规则是根据UML模型元素的特点和C++语言的代码结构建立的。自动生成代码时,首先输入符合UML元模型规则的UML模型,然后根据元模型的转换规则生成C++代码,其中类图生成C++中的类,顺序图生成方法内部的具体实现。

1.1 类图元模型

UML的元模型定义了使用UML描述对象模型的完整语法规则[10],图2为类图的元模型。UML类图中的类与元模型中的Class对应,属性和操作与Attribute和Operation对应。操作的参数对应Parameter,其中kind表示该参数的类型,若kind=in表示该参数为调用操作时传递的参数,kind=out则表示该参数为操作的返回值。各个类之间的关联关系用Association表示,Association End记录关联端的名称和属性。属性和参数的类型用Classifier表示。

1.2 顺序图元模型

图3为顺序图的元模型。一个顺序图用来描述类中的一个方法,对应元模型中的Interaction、Collaboration和Operation。其中Operation用来记录该顺序图所描述的方法的名称和可见性。顺序图中的对象对应元模型中的Classifier Role,不同对象间通信的消息对应Message,消息中要执行的动作对应Action,该动作执行的条件用recurrence表示,动作的内容用Request表示。动作分为调用(Call Action)、创建(Create Action)、发送(Send Action)、返回(Return Action)以及销毁(Destroy Action)。调用和创建操作的返回值用Return Var表示。参数的类型记录在Classifier中。

2 转换规则

下面介绍UML类图和顺序图到C++代码的转换规则。为了清楚准确地描述转换规则,UML模型元素使用文献[11]中定义的元素,转换规则中用到的标记如表1所示。转换规则使用表格描述,其中第一列为待转换的模型元素,第二列为该模型元素对应的元模型,第三列为该元模型对应的转换规则。

2.1 类图的转换规则

依据UML模型和C++代码的特性,得出类图和C++代码的关系为:UML模型中的类、属性、操作分别对应C++中的类、成员变量、成员函数。因此,UML类图到C++代码的转换规则包括类的转换规则、属性和操作的转换规则。

规则1 类的转换规则,如表2所示。待转换的模型元素是一个有名称的类,元模型中对象c的属性name记录了该类的名称。转换的第一步是.h文件(HFILE)和.cpp文件(CFILE)的生成,如表2转换规则第一行所示。.h文件包括头文件的引用IN-CLUDE、成员变量ATTRIBUTE和成员函数OPERATIONH的声明,被规则2中的内容替换。非终结符号c.name表示本规则所描述类的类名,被第一列中的类名所替换,语句#ifndef和#define后的c.name全部大写。在C++中,通常成员变量是私有的,成员函数是公有的,分别使用终结符号描述,如转换规则第二行所示。.cpp文件包括对应头文件的引用和成员函数OPERATIONC的具体实现,如转换规则第三行所示。

规则2 属性和操作的转换规则,如表3所示。待转换的是一个包含属性和操作的类,元模型中对象o和a分别记录操作和属性的名称,p1、p2分别为操作的参数和返回值,c1,c2,c3对应属性、参数、返回值的类型。转换规则的第一行定义了AT-TRIBUTE的转换过程,表示属性的类型和名称,二者组合完成了C++中成员变量的声明。该转换规则中的符号“_”是带下划线的空格,表示直接生成代码中的空格。OP-ERATIONH的转换过程与此相同。OPERATIONC的具体实现被顺序图生成的代码所替换,用非终结符号SEQUENCE表示。具体如规则4所示。

下面通过Reader类描述类转换到.h文件的过程,如表4所示,Reader类有一个int类型的属性id和一个返回值类型是void的操作create()。根据其元模型,对应的转换规则分别包括属性、操作、和参数的转换规则。根据规则1生成的代码如表中转换过程第一行所示,ATTRIBUTE和OPERATION还需要做进一步的转换,其他部分为最终生成的代码。根据规则2生成的代码如表中第二到四行所示,属性和操作的声明分别为int id和void create(int id)。最后经过合并,得到的代码如下所示。

规则3 关联关系的转规则,如表5所示。元模型中c1,c2表示两个相互关联的类,它们之间的关联关系用a记录。转换规则中定义了在Class A中添加对Class B的引用,用符号IN-CLUDE表示。

2.2 顺序图的转换规则

依据UML模型和C++代码的特性,得出顺序图和C++代码的关系为:UML顺序图中的内容对应C++成员函数的具体实现细节,顺序图中的分支、函数调用、对象创建分别对应C++中的if语句、“.”运算符、new关键字。因此,顺序图到C++代码的转换规则包括顺序图的转换规则、条件的转换规则、变量赋值的转换规则、对象创建的转换规则、方法调用的转换规则、消息发送的转换规则。消息返回和对象销毁操作不需要生成对应的代码。

规则4 顺序图的转换规则,如表6所示。对象o表示该顺序图是方法oper()的具体实现。非终结符号SEQUENCE被LOCALDATA和MESSAGE替换,说明一个方法的实现细节中包括局部变量的定义以及各对象之间相互传递消息的过程。

规则5 条件的转换规则,如表7所示。对象a向对象b发送了一个包含条件的消息。元模型中对象m的属性recurrence记录了条件的内容,当该条件满足时,执行这个消息上的操作。C++中使用if语句表示条件,如表中第三列所示。

规则6 变量赋值的转换规则,如表8所示。将Class B的方法oper()的返回值赋给变量x,元模型中对象rv表示变量的名称,r记录了方法的名称,c表示函数的返回值类型即变量的类型。转换规则的第一行显示了变量x的定义,第二行中非终结符号ASIGNMENT表示该变量会被赋值,它可以被函数的返回值赋值,如规则8所示,也可以被常量或表达式赋值。

规则7 对象创建的转换规则,如表9所示。“<<create>>”表示该消息是一个创建对象的操作。元模型中r表示待创建的对象的名称,p和c2表示参数的名称和类型。C++中有两种创建对象的方式,分别为Class Name object(param)和ClassName*object=new Class Name(param)。为了避免用户使用完对象后忘记删除而造成内存泄露,本文采用第一种对象创建的方法。转换规则第一行定义了创建对象时需要使用的参数,第二行MESSAGE生成对象创建的代码,第三行中非终结符号PARA转换为待传递的参数(PARAMETER包含参数的类型和名称,PARA仅包含参数的名称)。

规则8 方法调用的转换规则,如表10所示。消息的内容为调用对象object B中的方法oper()。元模型中cr记录对象的名称,r表示方法的名称,p和c2表示参数的名称及类型。方法调用包括其他对象方法的调用和对象自身方法的调用。C++中使用符号“.”访问成员函数,转换规则的第二行显示了调用其他对象的方法并将结果赋值给一个变量的规则,当调用自身方法时,去掉即可。无返回值的方法的转换规则如表中第四行所示。

规则9 消息发送的转换规则,如表11所示。消息中不包含任何方法调用或者对象创建的内容,元模型中r记录了消息的内容。消息发送包括发送到其他对象的消息和发送给自身的反身消息。二者都只需直接将消息中的内容直接生成代码,如表中第三列所示。

3 实例分析

本文以图书管理系统为例,描述如何结合类图和顺序图生成包含结构和行为信息的C++代码。为了便于理解,对实例进行了简化,只给出了一个概念性的模型。该模型包括图书Book、读者Reader、借书记录Record以及系统交互界面Sys Interface四个类,如图4所示。读者可以使用该系统借书、还书、查看书籍的详细信息。

图5是Sys Interface类中方法return()对应的顺序图。还书时,系统首先提示用户输入图书编号book ID,并根据该编号创建一个Book类的对象b,调用search()方法将该书的信息从数据库读入b中。然后将该书的数量加1,调用modify()方法将更新后的结果保存至数据库中。最后创建一个图书编号为book ID,读者编号为reader ID的Record对象rc,调用该对象的方法del()在数据库中删掉该条借阅记录。

类Sys Interface生成代码的过程为:

(1)应用规则1,生成Sys Interface.h和Sys Interface.cpp文件;

(2)应用规则2,生成Sys Interface.h文件中的成员变量choice、book ID、reader ID和成员函数run()、login()、borrow()、return()、display Book()的声明,Sys Interface.cpp文件中成员函数run()、login()、borrow()、return()、display Book()的框架;

(3)应用规则3,生成Sys Interface.h文件中对Book.h、Record.h、Reader.h文件的引用;

(4)应用规则4,生成return()函数的具体实现结构,先声明变量,然后顺序显示对象间传递的消息;

(5)应用规则9,生成提示用户输入图书编号,并存储该编号到变量book ID的语句;

(6)应用规则7,生成创建Book类的对象b的语句;

(7)应用规则8,生成调用对象b的方法search()的语句;

(8)应用规则6和规则8,生成变量num的声明和赋值语句;

(9)应用规则9,生成变量num加1操作的语句;

(10)应用规则8,生成调用对象b的方法set Num()和modify()的语句;

(11)应用规则7,生成类Record的对象rc的创建语句;

(12)应用规则8,生成调用对象rc的方法del()的语句;

经过以上步骤后自动生成的代码如表12所示,由于篇幅有限,Sys Interface.cpp中没有列出run()、login()、display Book()的框架。结果显示,在search()、modify()、get Num()、set Num()、del()已定义的条件下,自动生成的return()方法清楚地描述了还书操作的执行流程,是可执行的C++代码。由此可见,可以使用细粒度的顺序图描述各个方法的动态行为信息,应用本文提出的转换规则生成与图书管理系统相接近的C++代码。与多数文献中提出的只能生成代码框架的方法相比,本文提出的方法可以生成内容更加完整的代码。

根据以上研究成果,本文实现了一个基于PSM的代码自动生成工具,该工具采用Eclipse插件开发的方式,元模型使用基于XML的元数据表示方法,转换规则使用VTL编写的模板实现,代码生成器使用JDom技术解析XML文件内容,然后使用Velocity引擎根据模板的访问请求返回相应的模型数据并与代码模板合并生成目标代码。如图6所示,其中包括Sys Interface类对应的XML文件、类图到C++代码的转换模板、自动生成的C++代码。由于时间有限,顺序图到C++代码的转换模板还未完成。Veolcity技术的使用提高了代码的生成效率与代码模板的灵活度,从而为生成可执行的代码提供了技术支持。

4 结语

本文描述了一种结合类图和顺序图生成具有结构和行为信息的C++代码的方法。先将UML模型中的各个元素映射到相应的元模型,然后根据元模型的转换规则逐步生成C++代码。与多数文献中提出的只能生成C++代码框架的方法相比,本文提出的方法可以生成内容更加完整的代码,减少了编程人员手动添加代码的工作,从而提高了软件的开发效率和软件产品的质量。由于顺序图不易于描述代码中复杂的逻辑信息,所以部分逻辑复杂的代码需要编程人员手动添加或者参考活动图的信息。此外本论文只关注了类图和顺序图中的主要模型元素,类图中的关联类、受限关联以及顺序图中的片段都还没有相应的转换规则。所以,下一步将继续完善类图和顺序图的转换规则并提出活动图的转换规则。

参考文献

[1]Anneke Kleppe,Jos Warmer,Wim Bast.解析MDA[M].鲍志云,译.北京:人民邮电出版社,2004.

[2]刘辉,麻志毅,邵维忠.元建模技术研究进展[J].软件学报,2008,19(6):1317-1327.

[3]Abilio G Parada,Eliane Siegert,Lisane B de Brisolara.Generationgjava code from UML class and sequence diagrams[C]//2011 BrazilianSymposium on Computing System Engineering(SBESC).Pelotas,Brazil,2011.

[4]Usman M,Nadeem A.Automatic generation of java code from UML di-agrams using UJECTOR[C]//International Journal of Software Engi-neering and its applications(IJSEIA),2009,3.

[5]Mathupays Thongmak,Pornsiri Muenchaisri.Design of rules for trans-forming UML sequence diagrams into java code[C]//Proceedings ofNinth Asia-Pacific Software Engineering Conference.Gold Coast,Aus-tralia,2002.

[6]Dan Regep,Fabrice Kordon.Using metascribe to prototype an UML toC++/Ada code generator[C]//11th International Workshop on Rap-id System Prototyping.Paris,France,2000.

[7]由志远.基于MDA的嵌入式软件代码生成器设计与实现[D].西安:西安电子科技大学,2010.

[8]Deuk Kyu Kum,Soo Dong Kim.A systematic method to generate.Netcomponents from MDA/PSM for pervasive service[C]//Fourth Inter-national Conference on Software Engineering Research,Managementand Applications.Washington,USA,2006.

[9]Jichen Fu,Wei Hao,Farlkh B Bastani.Model-Driven Development:Where Does the Code Come from?[C]//Fifth IEEE International Confer-ence on Semantic Computing.Palo Alto.USA,2011.

[10]OMG.UML Semantics.Version 1.1[R].The Object Management Group,Document ad/97-08-05,Framingham MA,1997.

代码自动生成器 篇7

Think PHP是笔者常用的一个轻量级国产PHP开发框架, 但在开发过程中, 发现有大量类似但不完全重复的代码编写工作, 比如重复编写一些简单的数据库增删改查的操作, 编写前台表单、样式表等等。除了数据库设计不同之外, 界面、操作步骤等基本类似, 显得重复而没有必要。因此, 考虑设计一个通用的代码生成器来完成这些工作, 从而有效地减少开发工作量, 将精力集中于核心业务逻辑。

2设计思路

通过分析关系数据库操作的一些共性, 根据面向对象的思想和分层架构设计, 预置了一些与数据库相关的界面模板与操作的常用代码模板, 根据具体项目需要和设定, 不用写一行代码, 就能完成特定数据库表的增删改查的操作和相关界面的模板设计工作。主要包括以下功能:

1.1 生成CURD操作的HTML界面及后台代码

CURD是一个数据库技术中的缩写词, 它代表了数据库的创建 (Create) 、更新 (Update) 、读取 (Read) 和删除 (Delete) 操作。设计流程是:在系统界面中, 选择数据库类型 (My Sql或Sql Lite) , 列出所有数据库, 选择相应的数据库、数据表, 并设置好表间关系, 及相关查询代码及显示要求后, 点击确定, 基于模板自动生成关于该数据表的增加、删除、修改、浏览的基本HTML显示界面, 以及对应的后台数据库控制器操作代码, 并且按照think PHP的MVC模式的要求分目录存放。之后, 简单做一些修改就能满足项目需要。

1.2 生成通用的注册登录模块

任何一个系统, 都会有一些近似的注册登录等基本功能, 为此, 将其整合在了代码生成器中。主要包括新用户注册、登录、密码修改、密码找回等功能。

1.3 生成通用的后台管理模块

后台管理模板比较用常见, 不过为了更加方便, 将其与代码生成器的封装、整合在一起, 有利于后期的维护, 能够最大程度的简化劳动。

3 代码生成器实现的关键步骤

3.1 解决模板代码的冲突问题

Think Php是MVC模式架构的框架, 其最终生成的代码是基于模板机制的。而代码生成器的原理, 也是利用预置的模板生成符合当前项目需要的文件。因此, 预置的模板实际上是模板之模板。设计的关键是需要注意模板代码的冲突问题。在代码生成器中主要传入的模板变量是关于数据库的结构信息, 如表名、字段名、主键等, 而最终生成的代码还必须能够通过模板解析。例如, 在最终HTML界面中需要的是形如{$rs.name}的变量, 在代码生成器的模板中则需要写成"$"."rs.$a Field Name"的形式。

3.2 了解文件系统、数据库系统的操作方法

主要通过定义了下面的一些功能函数实现:

获取子目录列表function get Dir List ($dir) 创建目录function create Dir ($fullpath)

读取module名称列表function get Module Name List ()

获取表名列表function get Table Name List ()

获取字段列表function get Table Field Arr ($table)

获取表的主键function get Key Field Name ($table)

把带下划线的表名转换为驼峰命名 (首字母大写)

function table Name To Model Name ($table Name) 把带下划线的列名转换为驼峰命名 (首字母小写)

function Field Name To Var Name ($Field Name)

3.3 生成Html模板界面

生成Html界面时, 需要设置数据字段的显示方式, 即设置用Input、Radio、Check Box等哪一种表单元素来显示字段值, 对此, 需要利用自定义函数判断。

4 结语

在进行Web程序开发时, 不同的站点或系统都会有一些共同的操作, 如果每次都要重新编写代码既费时间, 又费精力。通过代码生成器, 能够实现通用模块代码的自动生成, 特别是实现数据表的基类代码的自动生成, 包括生成属性、添加、修改、删除、查询、存在性、Model类构造等基础代码片断, 增强了代码的可复用性、可维护性, 使得在开发过程中可以节省大量机械录入的时间和重复劳动, 而将精力集中于核心业务逻辑, 更加轻松地进行项目开发。因此, 设计一个通用的代码生成器显得非常有必要, 可以有效地减少了Web开发的工作量, 且提高了自已开发时间和维护成本, 给开发的工作带来了便利。

摘要:在基于ThinkPHP框架的多个web站点开发过程中, , 发现有大量类似但不完全重复的代码编写工作, 为了便于开发, 减少重复劳动, 本文基于ThinkPHP设计了一种代码生成器, 通过简单配置, 能够自动生成一些通用的界面与操作代码, 从而可以节省大量机械录入的时间和重复劳动, 将精力集中于核心业务逻辑的开发。

关键词:ThinkPHP框架,代码生成器,模板

参考文献

[1]王池李隐峰基于ThinkPHP的微课教学竞赛系统设计《电子科技》2014.10

上一篇:逻辑结构框架下一篇:导学艺术