摘 要: 本文提出并实现了一种数据驱动的命令界面生成方案, 以一致的方式生成所有命令的界面元素,能方便灵活地适应命令的修改变化。
关键词: 数据驱动;命令; Java
在典型的企业应用软件中,应用一般会提供一组命令作为用户与应用程序之间的接口。随着企业需求的变化和技术的发展,要求对原来的命令需要做出调整,比如增加命令,修改命令参数等,这可能需要修改应用程序,以生成调整后的命令界面。本文提出并实现了一种数据驱动的命令界面生成方案,该方案以一致的方式来处理所有命令,最大限度地保证命令的增加、删除、修改,不需要或很少需要修改应用程序。
1 数据驱动方案的提出和思想
通常情况下,应用程序根据自己的业务逻辑进行界面设计, 对于一条具体的命令,开发人员需要编写界面生成代码以生成该命令的界面元素,如菜单项、参数输入对话框等.在应用的命令数量不大时,这是比较直接的做法.但当应用包含有成百上千条命令时,还要逐一地为每条命令生成界面元素,无疑是件繁琐的事情。此外,随着应用的升级,可能要求对原有的命令系统做出修改,这又要求修改代码以生成修改后的命令界面元素。我们希望能有一种实现方法可以方便灵活生成命令的界面元素并适应命令将来调整的需要,而对我们程序的影响最小。
考察应用的所有命令可发现,虽然各命令的功能意义不同,但命令组成形式却有很大的相似性,都包括命令标识和零个或多个参数,而且为每条命令编写的界面生成代码也非常近似。因此我们可以以一种统一的方法来处理所有命令。数据驱动的命令界面生成方案的主要思想正基于此,以某种方式对应用的所有命令统一进行描述,通过描述数据来驱动所有命令的界面元素生成。本文使用数据库表完成对所有命令的原始描述。
参数的性质是通过其数据类型来反映的,只需根据实际应用,定义本应用中参数可能的各种数据类型.而数据类型的种类总是有限的,通过对每一种数据类型给出其处理办法,就可以实现对为数众多的参数的处理转为对有限种的数据类型的处理。
2 命令的数据库表描述
以数据库表中对命令的描述为出发点, 以后命令的增加、删除、修改及命令参数的变动只需修改描述表中的相关项.命令一般包括命令标识和参数,但为更有效地对命令进行组织管理和适应更复杂应用的需要,对命令的描述通过定义命令类型描述表、命令描述表、命令参数描述表、枚举描述表四级结构来完成.命令类型字段和命令字段联合确定一条唯一的命令,提供直观的名字字符和数值编码两种方式以适应不同需要。参数表中定义了参数类型和取值要求,枚举表是为特殊的参数类型设置的,其取值是在一些选择项中选取。各级表除了给出本表定义对象的基本属性外,如果有下级元素,还给出了下级元素的个数及其在下级表中的位置,通过这种方式将一条命令的各构成部分关联起来.下面给出这种表结构的一个简单示例。
· 命令类型描述表:描述命令的分类.
| 唯一标志 | 编号 | 名字 | 命令的个数 | 命令描述位置 |
| ct_00010 | 248 | 系统管理类 | 2 | c_00010 |
表1 命令类型描述
· 命令描述表: 描述具体命令
| 唯一标志 | 编号 | 名字 | 参数的个数 | 参数描述位置 |
| c_00010 | 1 | 系统联络请求 | 1 | p_00010 |
| c_00011 | 2 | 系统复位 | 0 | |
表2 命令描述表
· 命令参数描述表: 描述各命令的参数.参数的值是在用户调用命令时设定的,事先无法确定.我们只是对参数的性质做出一些约束。数据类型的种类视具体应用而定,应用可以为每种类型指定一数值编号,在表中填写参数数据类型的编号值。参数的最大值最小值给出了参数的取值范围或长度限制。
| 唯一标志 | 名字 | 数据类型 | 最大值 | 最小值 | 枚举的个数 | 枚举描述位置 |
| p_00010 | 是否要求响应 | 9 | | | 2 | e_00010 |
| p_00020 | 源文件名 | 13 | 32 | | 0 | |
表3 命令参数描述表
· 枚举描述表:给出枚举类型参数的枚举项
| 唯一标志 | 枚举名 | 枚举值 |
| e_00010 | 要求响应 | 1 |
| e_00011 | 不要求响应 | 0 |
表4:枚举描述表
以上表1只表4的内容仅提供一般性的示范,实际应用可根据业务逻辑的需要定义自己的命令内容,命令的规模不受限制.
3 数据驱动方案的Java语言实现
3.1 命令的内存结构
为了在程序中反映命令结构,定义CmdType、Cmd、CmdField、Enum四个类分别与数据库中的命令类型描述表、命令描述表、命令参数描述表、枚举描述表相对应.每个类包含与其对应表中各列所描述的属性,表的记录在读表到内存时表现为类的实例。下面以其中的一个类CmdType来说明.
public class CmdType{ public String key; public short code; public String name; public short childCount; public String childPointer; public Cmd[] cmds; public Cmd[] getCmds() throws IOException { … /* implementation code */ } } |
在CmdType类中, 从key到 childPointer之间的属性与命令类型描述表中唯一标志到命令描述位置的各列对应,数组cmds[]表示该命令类型所包含的命令,可由getCmds方法访问数据库得到。其他三个类的定义与CmdType相似,因Enum类已经是命令结构的最后一级,故不提供得到下一级对象的方法。
应用程序启动时访问数据库的命令类型描述表以获得命令结构层次中的第一级对象,结果保存在cmdTypes数组中。可以根据应用对内存和速度的要求决定是否需要读下一级表数据到内存。
3.2 界面元素的生成
应用程序可以为用户提供多种方式来调用命令,例如下拉菜单、弹出式菜单、树型菜单、命令行、图形浏览菜单等。创建这些界面元素只需根据内存中命令的数据结构,其内容包含在从数据库中读出的cmdTypes数组对象中。其中命令行方式在界面创建时不需要用到命令的内存结构,但可以利用内存结构帮助用户完成命令和参数输入。
下面的代码说明在Java语言下如何利用命令结构在界面上生成命令的树型菜单,假设命令要添加于父节点father下。
DefaultMutableTreeNode node; DefaultMutableTreeNode childnode; for(int i = 0; i < cmdTypes.length; i++) { node = new DefaultMutableTreeNode(); node.setUserObject(cmdTypes); node.setAllowsChildren(true); father.add(node); cmds = cmdTypes.getCmds(); if(cmds == null ) continue; for(int j = 0;j<cmds.length;j++) { childnode = new DefaultMutableTreeNode(); childnode.setUserObject(cmds[j]); childnode.setAllowsChildren(false); node.add( childnode ); } } |
可以看出,只需简单使用两重循环,就可为应用的所有命令在界面上生成命令导航树。
下面说明如何为所有命令,实现一种通用一致的参数输入方式.根据我们的命令结构组织方式,如果用户选择了某一Cmd节点,则其所需的参数在该Cmd对象的cmdFields数组中描述。对每一个参数,在界面上表现为一Label-Component对形式。Laber用于标识参数,Component组件供用户输入参数的实际值。每个参数在界面上占一行, 按GridBagLayout布局加入到参数面板中.这部分代码示例如下:
for (int i = 0; i < cmdFields.length; i++){ label = new JLabel(cmdFields.name); …/*根据参数内容设置label的其他属性,如label的提示信息tip等*/ gbc.anchor = GridBagConstraints.EAST; gbc.gridwidth = GridBagConstraints.RELATIVE; paraPanel.add( label, gbc); gbc.anchor = GridBagConstraints.WEST; gbc.gridwidth = GridBagConstraints.REMAINDER; switch(cmdFields.type){ case 0: component = new JTextField(16) /*不妨设参数类型为0时对应JTextField组件*/ …/*根据参数内容添加对组件的控制*/ paraPanel.add( component,gbc); break; case 1: component = new JComboBox() /*假设参数类型为1时对应 JComboBox组件*/ …/*根据参数内容添加对组件的控制*/ paraPanel.add( component,gbc); break; … … case n: …/* 添加类型为n时的组件*/ default: …/*参数数据类型未定义*/ } } |
参数类型上的差异,在界面上表现为所添加的Component种类不同。我们只需为应用的每一种数据类型确定一种Component供用户输入.多数类型,在JTextField 组件下就能完成参数输入,输入的同时可以根据CmdField对象对其输入范围作出限定.我们的方案在设计时已经考虑到参数取值是枚举的情况,对枚举类型参数,其可能的取值项被添加到一个JList或JComboBox组件中。用户也可以为自己的数据类型定制一个专用的输入组件。一个应用程序到底设有哪些数据类型,可视具体应用情况而定.简单的情况提供字串值和二进制值两种类型就可以完成所有输入。更一般的情况可包括常用的整数类型、浮点类型、时间类型等。我们的方案不直接支持复杂的构造类型,一个构造类型的参数可视为由其包含的多个基本类型参数组成。
4 结束语
数据驱动的命令界面生成方案充分考虑了命令间的相似性,以一致的方式生成所有命令的界面元素,具有更好的伸缩性和扩展性.本方案非常有利于大规模命令的实现并能方便地适应命令的修改变化。本方案同时也有利于用户界面和业务逻辑分离.命令可以由对命令功能含义非常熟悉的业务人员来定义,而界面设计人员可以在对命令毫无所知的情况下根据业务人员提供的命令描述在界面上生成所需要的命令界面元素。